Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 991
Danra Avatar asked Mar 25 '18 08:03

Danra


People also ask

What is template argument deduction?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

What are template arguments enlist types of template arguments?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

Why do we use template template parameter?

8. Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.


2 Answers

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;});
};
like image 155
chtz Avatar answered Sep 22 '22 07:09

chtz


You could do something like this:

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

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

like image 27
Barry Avatar answered Sep 21 '22 07:09

Barry