简体   繁体   中英

Template specialization with multiple variadic templates

In my last question I received great help in getting a template specialization to work. Now I need a little extension. I want two specializations for these statements:

int main()
{
    // First specialization
    holder_ext<person> h1;
    holder_ext<person, &person::age> h2;
    holder_ext<int> h3;

    // Second specialization
    holder_ext<person, &person::age, &person::name> h4;
}

My class person looks like this:

class person
{
private:
    std::string name_;
    int age_;
public:
    person(const std::string &name)
        : name_(name), age_(56)
    {}
    void age(int a) { age_ = i; }
    void name(const std::string &n) { name_ = n; }
};

The special thing is, that the two member functions have different parameter types. So I can't use the same variadic template member function for both. I tried it with two different variadic templates. But that doesn't work. Also default values for the member functions do not work.

Does anybody have a good hint for me?

This is the solution with one member function (thanks to Pubby ):

template < class T, void (std::conditional<std::is_class<T>::value, T, struct dummy>::type::* ...FUNC)(int)> class holder;

template < class T, void (T::*FUNC)(int)>
class holder<T, FUNC>
{
public:
    explicit holder() : setter(FUNC) { std::cout << "func\n"; }
private:
    std::function<void (value_type&, int)> setter;
};

template < class T>
class holder<T>
{
public:
    explicit holder() { std::cout << "plain\n"; }
};

Thanks again in advance!

PS: And no, I won't come up in two days with "what must do with three, four, five member functions"? ;-)

For a fully generic solution you would be hitting a problem that cannot be resolved: The type of non-type template argument cannot be inferred, so it must be explicit in the template declaration, so there is no way of telling the template that you want multiple pointer-to-member arguments each of which will have a yet unknown type.

I haven't played with C++11 enough, but you could try forcing an ordering on the member template arguments and provide all signatures in the template:

template <typename T, 
          void (std::conditional<...>::type*)(int),
          void (std::conditional<...>::type*)(const std::string&)>

Again, it might work or it might not...

Finally I found a solution for my problem. It is a mix between variadic templates and template specilization:

template < class T,
void (std::conditional<std::is_base_of<object, T>::value, T, struct dummy>::type::*FUNC1)(int) = nullptr,
void (std::conditional<std::is_base_of<object, T>::value, T, struct dummy>::type::* ...FUNC2)(const std::string&)
>
class holder_ext;

template < class T,
void (std::conditional<std::is_base_of<object, T>::value, T, struct dummy>::type::*FUNC1)(int),
void (std::conditional<std::is_base_of<object, T>::value, T, struct dummy>::type::*FUNC2)(const std::string&)
>
class holder_ext<T, FUNC1, FUNC2>
{
public:
    holder_ext() { std::cout << "func 2 test\n"; }
};

template < class T,
void (std::conditional<std::is_base_of<object, T>::value, T, struct dummy>::type::*FUNC1)(int)
>
class holder_ext<T, FUNC1>
{
public:
    holder_ext() { std::cout << "func 1 test\n"; }
};

I use a not implemented declaration and define two specializations. One with both member function and the other one for all other cases.

If there is a better solution dont't hesitate to tell me.

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