Question

Is there a way to make a lambda decay to a pointer, without explicitly casting to the right signature? This would tidy some code:

template<typename T> T call(T(*func)()){ return func(); }
int ptr(){ return 0; }
int main(){
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; }));
    auto ret3 = call([]{ return 0; });  //won't compile
}

It's evident that a call to call works only if the lambda decays to a pointer, but I'm guessing that that can happen only after the right function overload/template is chosen. Unfortunately I can only think of solutions that involve templates to make a lambda with any signature decay, so I'm back to square one.

Was it helpful?

Solution

You can change your lambda to use the unary + operator: +[]{ return 0; }

This works because unary plus can be applied to pointers, and will trigger the implicit conversion to function pointer.

OTHER TIPS

Why would you unnecessarily constrain yourself to function pointers without defaulted arguments and lambdas without captures, completely ruling out the huge family of functors (e.g. std::function, any results of std::bind and everything else that has a suitable operator())?

Better just broaden your function signature:

template <typename F> 
auto call(F func) -> decltype(func()) { 
  return func(); 
}

int ptr() { return 0; }

int g(int i = 0) {return i;}

int main() {
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; })); //tedious, but works
    auto ret3 = call([]{ return 0; });  //ok now.

    auto ret4 = call(g); //ok now!
    int i = 42;
    auto ret5 = call([=]{return i;}); //works, too!
    auto ret6 = call(std::bind(g, i)); //and so on...
}

As a TL;DR; implementation of the @Simple proposal, I have write a simple test as follow:

SCENARIO("decay_equiv", "")
{
    auto callback = +[](struct mosquitto *, void *,
                        const struct mosquitto_message *)->void{};

    typedef typename std::is_same<
            typename std::decay<decltype(callback)>::type,
            typename std::decay<void (*)(struct mosquitto *, void *, const struct mosquitto_message *)>::type
                    >::type s;
    std::cout << s::value << std::endl;
}

Try it removing the + in the callback definition and everything stop to work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top