Why cant we declare std::function with auto

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

>Solution :

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.

Leave a Reply