c++ - Recursive variadic template with empty parameter pack (to avoid duplication for base case) -
i experimenting c++ recursive templates , not know why template not working.
say want define recursive function takes variable number of arguments (for different types).
i've have looked @ many examples of variadic templates, , i've seen far use separate template specialisation specify base case.
however, think nicer (in cases @ least) use single template, defines base case recursive cases.
i think approach nice if have lot of common logic in function, have duplicate base case instance (exact same code in 2 different places).
the second template in example below supposed solution. think template should functioning on it's own. not case.
without first template, code not compile:
error: no matching function call 'add_elems' return head[i] + add_elems(i, second, tail...); ^~~~~~~~~ in instantiation of function template specialization 'add_elems<double, std::__1::vector<double, std::__1::allocator<double> >>' requested here ...
apparently template braks when tail
consists of 1 parameter. shouldn't add_elems(i, second, tail...)
still valid template template<typename v, typename s, typename... t> v add_elems(size_t i, const std::vector<v>& head, const s& second, const t&... tail)
empty tail
?
i not know if compiler dependent, using clang.
#include <iostream> #include <vector> /* template exact same below template empty parameter pack tail. want code working without specialisation */ template<typename v, typename s> v add_elems(size_t i, const std::vector<v>& head, const s& second) { /* imagine more code here */ return head[i] + second[i]; } template<typename v, typename s, typename... t> v add_elems(size_t i, const std::vector<v>& head, const s& second, const t&... tail) { /* imagine more code here (the same above) */ if (sizeof...(tail) > 0) return head[i] + add_elems(i, second, tail...); else return head[i] + second[i]; } int main() { std::vector<double> a({1, -3, -3}); std::vector<double> b({2, -2, 1}); std::vector<double> c({4, -4, -11}); std::vector<double> d({4, 10, 0}); std::cout << "result: " << add_elems(0, a, b, c, d); std::cout << " ," << add_elems(1, a, b, c, d); std::cout << " ," << add_elems(2, a, b, c, d); }
the problem if
statement not constexpr
. meaning code paths need compilable every potential call add_elems
this means end @ case tail
1 element, , compiler needs evaluate add_elems(size_t&, const, std::vector<double>&)
, doesn't exist because there's no second
argument.
if able have constexpr if
statement, work nicely because compiler wouldn't compile bad branch when evaluates false, , therefore wouldn't nonexistent function:
template<typename v, typename s, typename... t> v add_elems(size_t i, const std::vector<v>& head, const s& second, const t&... tail) { if constexpr (sizeof...(tail) > 0) return head[i] + add_elems(i, second, tail...); else return head[i] + second[i]; }
demo (requires clang 3.9.1 or greater , -std=c++1z
option.)
for it's worth, if have access c++17, can achieve unary right fold:
template<typename... t> decltype(auto) add_elems(size_t i, const t&... elems) { return (elems[i] + ...); }
demo 2 (requires clang 3.6.0 or greater , -std=c++1z
option.)
Comments
Post a Comment