简体   繁体   中英

Partial Specialization of a variadic template function

I have this function which should work recursively.

template <class C, typename ...Arguments>
void addStyleClassRecursive(C *c, Arguments... arg)
{        
    c->addStyleClass(arg...);
    for (unsigned int i=0; i<c->children().size(); ++i)
    {
        addStyleClassRecursive(c->children()[i], arg...);
    }       
}

Now it happens that at some point I hit a class ( Wt::WObject ) which has not the addStyleClass member function, so the compiler complains -rightly- about this problem. Ok. So I thought to specialize the code, adding a version for Wt::WObject :

template <class C=Wt::WObject, typename ...Arguments>
void addStyleClassRecursive(Wt::WObject *c, Arguments... arg)
{
    for (unsigned int i=0; i<c->children().size(); ++i)
    {
        addStyleClassRecursive(c->children()[i], arg...);
    }
}

This doesn't give a compiler error in itself, but it is utterly ignored (indeed the compiler keeps complaining about WObject not having the required member function, pointing to the same line within the general function).

So I tried to specialize it in this way

template <typename ...Arguments>
void addStyleClassRecursive<Wt::WObject, Arguments...>(Wt::WObject *c, Arguments... arg)
{
    for (unsigned int i=0; i<c->children().size(); ++i)
    {
        addStyleClassRecursive(c->children()[i], arg...);
    }
}

Now the compiler complains about

non-type partial specialization 'addStyleClassRecursive<Wt::WObject, Arguments ...>' is not allowed
 void addStyleClassRecursive<Wt::WObject, Arguments...>(Wt::WObject *c, Arguments... arg);
                                                                                        ^

So can anyone point out how to attain the required result?

You cannot partially specialize a function template.

What you can do is let the recursive template call a different function on its first variadic template arg, and then recursively call itself on the remainder of the arguments. Then you can fully specialize the helper function.

You can do something like this:

template <class C, typename ...Arguments>
auto addStyleClassRecursiveImpl(int, C *c, Arguments... arg)
-> decltype(c->addStyleClass(arg...), void()) {
    c->addStyleClass(arg...);
    // ... C has addStyleClass
}

template <class C, typename ...Arguments>
void addStyleClassRecursiveImpl(char, C *c, Arguments... arg) {
    // ... C has not addStyleClass
}

template <typename... T>
void addStyleClassRecursive(T ...&&t) {
    addStyleClassRecursiveImpl(0, std::forward<T>(t)...);
    // ...
}

The idea is to tag-dispatch the request to an internal implementation (called addStyleClassRecursiveImpl in the example) and use sfinae and function overloading to pick the right version up.


And of course, you cannot partially specialize a function template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM