recursive variadic template can't deduce argument

送分小仙女□ 提交于 2019-12-11 02:07:16

问题


I have a recursive function template where type 'T' is used internally but the variadic template argument is used only for generate the recursive template.

int qi(int t) {
    return 0;
}

template <typename T, typename... U>
int qi(int t) {
    //do stuff...
    return qi<U...>(t); // <--- error here
}

If I try to compile it, I get the error could not deduce template argument for 'T'. Why can't the function be deduced to the non template variant of qi (int qi(int t){}) ?


回答1:


The problem you're running into is that qi<>(int ) and qi(int ) are not the same call - the former is still a template, so the overload you attempted to write as your base case actually isn't. It's actually worse since the initially obvious solution:

template <>
int qi(int ) { ... }

since won't work since that isn't an explicit specialization of your qi (since your function template takes at least one type). The simplest thing would be to actually use arguments to overload with:

template <typename...> struct sequence { };

template <typename... T>
int qi(int t) { return qi_helper(t, sequence<T...>{} ); }

With:

template <typename T, typename... U>
int qi_helper(int t, sequence<T, U...> ) {
    // do stuff
    return qi_helper(t, sequence<U...>{}); 
}

int qi_helper(int t, sequence<> ) {
    // base case
}

You can accomplish a similar thing with a struct QiHelper<T...> that is specialized for the two cases (since you can partially specialize a class template).

If you didn't want to return anything, you could forward to a helper like this:

template <typename T> void qi_helper(int t) {
    /* logic for single type */
}

template <typename... T>
void qi(int t) {
    using swallow = int[];
    (void)swallow{0,
        (void(qi_helper<T>(t)), 0)...
    };
}

Depending on what you actually want to return, that may or may not still be possible.




回答2:


First, declare qi to take any number of template arguments, including zero arguments.

template <typename... TU>
extern
int qi(int t);

We must eventually provide an implementation of this. But first, we are allowed to provide any number of fully-specialized (not partially-specialized) templates. So, we implement the zero-argument one:

template < > 
int qi< >(int ) { 
    return 0;
}

It's a specialization (because there is a < after qi) and a full specialization (because the < > after template is empty.

We would like to implement the non-specialized qi template now. We're not allowed to do any partial specialization, and we don't want to do full specialization as that would mean having to implement every set of types you might use. So that means we must implement something with this signature: template <typename... TU> int qi(int t) ...

We're stuck with TU, and no obvious way to 'peel off' the T to be left with the pack U.... The simplest thing is to pass off the implementation to a helper function:

template<typename T, typename... U>
int qi_helper(int t) {
    // do any other interesting stuff
    return qi<U...>(t); 
}

template <typename... TU>
int qi(int t) {
    // just pass on the call to qi_helper
    return qi_helper<TU...>(t);
}


来源:https://stackoverflow.com/questions/31326458/recursive-variadic-template-cant-deduce-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!