lambda expression are objects (the type of that object is temporary defined by the compiler and any lambda has a different type) for which the compiler defines an operator(). In short there's no implicit conversion from lambda type to function pointer. In these cases I prefer to use std::function
which has an adequate constructor to handle lambda expressions.
So a possible solution would be replace raw function pointer with std::function
and encapsulate the lambda expression in a std::function
to be passed to the constructor.
#include <functional>
#include <iostream>
template<typename MsgType>
using SendFunctor = std::function<void(MsgType&)>;
template<typename MsgType>
struct Test {
Test(SendFunctor<MsgType> t) {
MsgType msg;
t(msg);
}
};
struct Message {};
template<typename MsgType>
Test(SendFunctor<MsgType>) -> Test<Message>;
int main()
{
SendFunctor<Message> f = [](Message&) { std::cout << "Hello2" << std::endl; };
Test test(f);
}
here's a live test
---- EDIT
Playing around a bit, I also solved the ambiguity in your deduction guide by using a struct helper to deduce the argument that takes a lambda expression, thanks to this answer which you can read for completeness.
here's the helper struct deducing the argument type of a lambda.
template<class C>
struct Get_LambdaFirstArg;
template<class C, class R, class Arg>
struct Get_LambdaFirstArg<R(C::*)(Arg&)const>{
using type = Arg;
};
template<class C, class R, class Arg>
struct Get_LambdaFirstArg<R(C::*)(Arg&)>{
using type = Arg;
};
Here's the new deduction guide defined to handle lambda expressions.
template<typename LambdaType>
Test(LambdaType) -> Test<typename Get_LambdaFirstArg<decltype(&LambdaType::operator())>::type>;
and here's a minimal example:
#include <functional>
#include <iostream>
template<typename MsgType>
using SendFunctor = std::function<void(MsgType&)>;
template<typename MsgType>
struct Test {
Test(SendFunctor<MsgType> t) {
MsgType msg;
t(msg);
}
};
template<class C>
struct Get_LambdaFirstArg;
template<class C, class R, class Arg>
struct Get_LambdaFirstArg<R(C::*)(Arg&)const>{
using type = Arg;
};
template<class C, class R, class Arg>
struct Get_LambdaFirstArg<R(C::*)(Arg&)>{
using type = Arg;
};
struct Message {};
template<typename MsgType>
Test(SendFunctor<MsgType>) -> Test<Message>;
template<typename LambdaType>
Test(LambdaType) -> Test<typename Get_LambdaFirstArg<decltype(&LambdaType::operator())>::type>;
int main()
{
Test test([](Message&) { std::cout << "Hello2" << std::endl; });
}
and here's a live test of that example.
-- EDIT
finally i better tested the answer of @apple apple and it seems I was doing something wrong.
Using the + to convert lambda to function pointer and solves the ambiguity in your deduction guide.