Newline
Newline

Reputation: 941

Function template taking function template

I'm learning concepts and templates. I'm trying to make a function template that will call another function template. Currently it works with lambda but not with a normal function.

// This also works with lambda but not the normal function:
//void callFunc(std::regular_invocable<T> auto invocable)

template<typename T>
void callFunc(auto invocable)
{
    invocable(T(5));
}

// Doesn't work, whether I use "T" or "auto"
//template<typename T>
void testFuncToPass(const auto& a)
{
    std::cout << a << " CALLED\n";
}

//...

auto lambda = [](const auto& a){std::cout << a << " CALLED\n";};

//callFunc<int>(testFuncToPass); // ERROR
callFunc<int>([](const auto& a){std::cout << a << " CALLED\n";});
callFunc<int>(lambda);

It says: "error : no matching function for call to 'callFunc'. candidate template ignored: couldn't infer template argument 'invocable:auto'"

Is what I'm trying to do doable? I also tried to use template template parameter but seems that only works for types, not for functions.

Upvotes: 2

Views: 62

Answers (1)

user4442671
user4442671

Reputation:

You are under the impression that

auto lambda = [](const auto& a){std::cout << a << " CALLED\n";};

is equivalent to

template<typename T>
void lambda(const T& a) { std::cout << a << " CALLED\n"; }

But it's not. It's actually equivalent to:

struct SomeType {
  template<typename T>
  void operator()(const T& a) const { std::cout << a << " CALLED\n"; }
};
SomeType lambda;

Fun fact: If your lambda captures values and/or references, they become private members of that struct, and marking the lambda as mutable simply removes the const. Lambdas are effectively just syntactic sugar on top of functors.

Is what I'm trying to do doable?

Unfortunately not as of the current standard. It is possible to accept a templated type as an argument (via some funky-looking syntax), but function templates are still off the table at the moment.

You pretty much have to declare a struct or a class with a templated operator() like in my example, or wrap them in a lambda:

callFunc<int>([](auto const& a){testFuncToPass(a);});

Upvotes: 3

Related Questions