I got following code:
template<typename T>
concept con1 = requires(T t, std::string s){
{ t[s] } -> std::same_as<std::string>;
};
using function_signature = std::function<void ( con1 auto functor)>; // ERROR!
while the compiler has no problem me defining the lambda directly:
auto lambda_1 = [](con1 auto functor){....}
The reason why I want the former to work is the following:
template<std::semiregular T>
class R{
T functor;
R() = default;
register_functor(T functor_) { functor = std::move(functor_);}
}
If I get to instantiate my class using the signature like:
auto rr = R<function_signature>();
I can get to register my functor at a later stage, and even change the function at run time as long as I keep the signature the same. Using the lambda directly means I am stuck with whatever my lambda is at the time I instantiate the class R
CodePudding user response:
auto
in a lambda parameter list doesn't represent one single automatically-inferred type like it would in a variable initialization, it represents that the lambda has a templated operator()
which has a whole parameterized family of function signatures.
You can't instantiate a template that expects a concrete type (and std::function
does) with a parameterized family of types. You could create a parameterized family of typedefs, each formed by instantiating std::function
:
template<con1 T> using function_signature = std::function<void (T)>;
But this doesn't get you any closer to being able to write R<function_signature>
. For that, you'd need template<template class T<U>> class R;
and then R
needs to somehow provide the type parameter T2
in T<T2> functor
.
In the end, it comes down to std::function
being a wrapper to a pointer-to-member function (among other flavors), and a pointer-to-member function cannot point to a whole template family of member functions.
This also fails:
auto lambda_1 = [](con1 auto functor){....};
auto pmf = &lambda_1::operator(); // cannot take address of template member function
Put another way, type-erasure doesn't work on templates. Instantiating the template requires its type.