2017-01-04 4 views
1

У меня есть сторонние библиотеки, которая реализует перегруженные функции с однородными входными параметрами, как:Преобразования вектора или массива в список аргументов в C++

int foo(int a); 
int foo(int a, int b); 
int foo(int a, int b, int c); 
... 

Теперь я хотел бы написать оболочку, которая будет принять параметры, упакованные в вектор (или, альтернативно, массив):

int foo_wrapper(vector<int>& foo_args); 

Как это сделать?

Я посмотрел на this answer on converting vector to tuple за подсказку, но он дает мне ошибку:

$ g++ -std=c++14 -o test.a test.cpp 
test.cpp: In function 'int main(int, char**)': 
test.cpp:23:20: error: no matching function for call to 'vectorToTuple(std::vector<int>&)' 
    vectorToTuple(v); 
        ^
test.cpp:16:6: note: candidate: template<long unsigned int N, class T> auto vectorToTuple(const std::vector<T>&) 
auto vectorToTuple(const std::vector<T>& v) { 
     ^~~~~~~~~~~~~ 
test.cpp:16:6: note: template argument deduction/substitution failed: 
test.cpp:23:20: note: couldn't deduce template parameter 'N' 
    vectorToTuple(v); 
        ^

с test.cpp быть

#include <iostream> 
#include <vector> 
#include <tuple> 
#include <utility> 

int foo(int a) {return a;}; 
int foo(int a, int b) {return a+b;}; 
int foo(int a, int b, int c) {return a+b+c;}; 

template <typename T, std::size_t... Indices> 
auto vectorToTupleHelper(const std::vector<T>& v, std::index_sequence<Indices...>) { 
    return std::make_tuple(v[Indices]...); 
} 

template <std::size_t N, typename T> 
auto vectorToTuple(const std::vector<T>& v) { 
    //assert(v.size() >= N); 
    return vectorToTupleHelper(v, std::make_index_sequence<N>()); 
} 

int main(int argc, char** argv) { 
    std::vector<int> v={1,2}; 
    vectorToTuple(v); 
} 
+0

Чтобы устранить эту ошибку, ответ очевиден, поставьте 'N':' vectorToTuple <2> (v); 'не знаю, действительно ли это решает вашу проблему, где вы вызываете' foo'? – imreal

+0

вы не можете с 'std :: vector <>'; разрешение перегрузки выполняется во время компиляции, но размер 'vector <>' известен только во время выполнения. –

ответ

5

Этот вопрос очень трудно обобщенно ответить std::vector но относительно простой с std::array или std::tuple. Поскольку вы указали в своем вопросе, что std::array будет в порядке, ваш пример может быть выполнен с минимальными усилиями.

#include <array> 
#include <iostream> 
#include <tuple> 
#include <utility> 

int foo(int a) {return a;}; 
int foo(int a, int b) {return a+b;}; 
int foo(int a, int b, int c) {return a+b+c;}; 

template <std::size_t N, typename T, std::size_t... Indices> 
auto call_foo_helper(const std::array<T, N>& v, std::index_sequence<Indices...>) { 
    return foo(std::get<Indices>(v)...); 
} 

template <std::size_t N, typename T> 
auto call_foo(const std::array<T, N>& v) { 
    return call_foo_helper<N>(v, std::make_index_sequence<N>()); 
} 

int main(int argc, char** argv) { 
    std::array<int, 2> v={1,2}; 
    auto x = call_foo(v); // x = 1 + 2 = 3 
    return 0; 
} 

Edit:

Это также работает для std::tuple путем изменения std::array к std::tuple и изменения заявления шаблона, чтобы соответствовать.

#include <iostream> 
#include <tuple> 
#include <utility> 

int foo(int a) {return a;}; 
double foo(int a, double b) {return a+b;}; 
double foo(int a, double b, int c) {return a+b+c;}; 

template <typename... T, std::size_t... Indices> 
auto call_foo_helper(const std::tuple<T...>& v, std::index_sequence<Indices...>) { 
    return foo(std::get<Indices>(v)...); 
} 

template <typename... T> 
auto call_foo(const std::tuple<T...>& v) { 
    return call_foo_helper(v, std::make_index_sequence<sizeof...(T)>()); 
} 

int main(int argc, char** argv) { 
    auto v = std::make_tuple(1, 2.0); 
    auto x = call_foo(v); 
    return 0; 
} 
+0

Хороший ответ, но он работает только в том случае, если все параметры перегруженных функций имеют один и тот же тип. –

+0

Тот же тип в порядке – Roman

+0

@FelixLauer не уверен, что это актуально, поскольку в самом вопросе все параметры одного типа тоже. – Eddge

2

Функция разрешения перегрузки выполняется во время компиляции, и так как размер std::vector<> известно лишь во время выполнения, вы должны выполнить код:

int foo_wrapper(std::vector<int>& foo_args) 
{ 
    switch (foo_args.size()) 
    { 
     case 1: return foo(foo_args[0]); 
     case 2: return foo(foo_args[0], foo_args[1]); 
     case 3: return foo(foo_args[0], foo_args[1], foo_args[2]); 
     default: 
      throw std::range_error("Incorrect number of arguments."); 
    } 
} 

int main(int argc, char** argv) { 
    std::vector<int> v = { 1,2 }; 
    std::cout << foo_wrapper(v); 
} 

Как уже упоминалось в another answer, то размер std::array<> известен во время компиляции, что позволяет использовать другое решение.

Смежные вопросы