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

Popular posts from this blog

Command prompt result in label. Python 2.7 -

javascript - How do I use URL parameters to change link href on page? -

amazon web services - AWS Route53 Trying To Get Site To Resolve To www -