4
votes

I have the following working code:

class person
{
private:
    int age_;
public:
    person() : age_(56) {}
    void age(int a) { age_ = i; }
}

template < class T, void (T::* ...FUNC)(int) > class holder;

template < class T, void (T::*FUNC)(int)>
class holder<T, FUNC>
{
public:
    typedef typename T::value_type value_type;
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"; }
};

int main()
{
    holder<person> h1;
    holder<person, &person::age> h2;

    // this does not work:
    holder<int> h3;
}

I know that in case of int (or any other non class, struct or union type) the code does not work because of the expect member function in the second template argument.

My question is how to change the code to make it work. I need it work that way, to make the use of my holder class simple.

I've tried it with type traits and also moved the member function pointer to the constructor of the class. Without success.

Any suggestions? Thanks in advance!

1
Traits are the way to go - what did not work with them?Björn Pollex
For testing a tried to make an int specialization with enable_if, but the compiler always mentioned the missing member function from the first holder definition.zussel

1 Answers

3
votes

Update: I got it to work with std::conditional:

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

Another possible solution is to use a subclass:

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

template <class T, bool IsClass = std::is_class<T>::value>
class holder;

template <class T>
class holder<T, true> : public class_holder<T>
{
public:
    template <void (T::*FUNC)(int) >
    class with_member : public class_holder<T, FUNC>
    {
    };
};

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

int main()
{
    holder<person> h1;
    holder<person>::with_member<&person::age> h2;
    holder<int> h3;
}

I haven't compiled this so tell me if something doesn't work.