Danra
Danra

Reputation: 9906

Template type deduction according to constructor argument

I have a class template whose constructor accepts a callable whose type is a template parameter. I would like to have that type deduced so I don't have to specify it whenever instantiating the class.

Unfortunately, the type deduction doesn't work in the example below. Is there a way to get it to work?

template<typename F>
class C {
public:
   C(F&& f) : m_f{f} {}
private:
   F m_f;
};

class D {
public:
    static int s() { return 0; }
private:
   C<decltype(&s)> c {&s}; // OK
   C<> c2 {&s};            // error, not enough template parameters
};

https://wandbox.org/permlink/8cphYR7lCvBA8ro4

Note this is similar to Can template parameter deduction be used in class data members? but here I'm asking about getting something similar to work, not about standard compliance.

One more note is that while re-specifiying the type of the template parameter in the example above is just a non-DRY inconvenience (which one of the answers below suggests solving with a macro), I'm not sure how it would be possible to have an instance of C with F being a non-global lambda function type (e.g. one that's defined on the spot), in case that instance is a data member. A technique which would allow that would be very powerful and useful, IMHO.

Upvotes: 5

Views: 510

Answers (2)

chtz
chtz

Reputation: 18809

If your main goal is to avoid typing &s twice, the pragmatic solution is to define a macro:

#define CC(name,value) decltype(C{value}) name{value}

class D {
public:
    static int s() { return 0; }
private:
    CC(c,&s);
    // lambda still not possible:
    // CC(c2,[](){return 42;});
};

Upvotes: 4

Barry
Barry

Reputation: 302653

You could do something like this:

decltype(C{&s}) c{&s};

But I'm not aware of a way to avoid duplicating the &s.

Upvotes: 3

Related Questions