2

I have the following code (simplified):

#include <functional>
template <typename... Args> void Callback(std::function<void(Args...)> f){
    // store f and call later
}
int main(){
    Callback<int, float>([](int a, float b){
        // do something
    });
}

The goal of this is to take some extra parameters, send off a packet, handle the response and call the lambda with the results The issue with this is, it doesnt take the lambda.

# g++ -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:8:3: error: no matching function for call to ‘Callback(main()::<lambda(int, float)>)’
test.cpp:8:3: note: candidate is:
test.cpp:2:34: note: template<class ... Args> void Callback(std::function<void(Args ...)>)
test.cpp:2:34: note:   template argument deduction/substitution failed:
test.cpp:8:3: note:   ‘main()::<lambda(int, float)>’ is not derived from ‘std::function<void(Args ...)>’

Is there any way to get this to work without going through the hassle of wrapping the lambda explicitly in a std::function?

Callback(std::function<void(int, float)>([](int a, float b){
    // do something
}));

Works flawlessly, even when omitting the Callback template arguments (like shown here). There is still the 'extra' std::function though.

Why cant it figure out the conversion on its own? It works for non-templates:

void B(std::function<void(int, float)> f){/* ... */};
int main(){
    B([](int a, float b){
        // do something
    });
}

For reference, I'm using

gcc version 4.7.2 (Debian 4.7.2-5)

Constructor
  • 7,273
  • 2
  • 24
  • 66
imer
  • 136
  • 1
  • 8
  • Just because a lambda is *convertible to* an `std::function` doesn't mean it *is* an `std::function`. How is the compiler supposed to figure out the `std::function` template arguments from an unrelated type? – Praetorian Jun 05 '14 at 18:43
  • 2
    Does [this](https://stackoverflow.com/q/13358672/241631) answer your question? Or [this](https://stackoverflow.com/q/9998402/241631)? – Praetorian Jun 05 '14 at 18:44
  • @Praetorian: It's able to do that just fine if the function does not contain template arguments (as described), so it should (i'd think) work for that case too – imer Jun 05 '14 at 18:50
  • Template argument deduction *is* where it's going awry, so of course it works if you take that out of the equation. Read the answers I linked to in my previous comment. – Praetorian Jun 05 '14 at 18:53

3 Answers3

3

You can use a dedicated cast. Once you have a tool like this

#include <functional>

using namespace std;

template<typename T>
struct memfun_type
{
    using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
    using type = std::function<Ret(Args...)>;
};

template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
    return func;
}

you can say FFL() to all lambda types to have them converted to what would be the correct version of std::function

int main()
{
    Callback(FFL([](int a, float b){
        // do something
    }));

    return 0;
}

Display

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
2

As Praetorian pointed out: this answers my question. I'm really baffled why you need to use suck a hack though. Code for reference:

#include <functional>
template <typename T> struct identity
{
  typedef T type;
};
template <typename... Args> void Callback(typename identity<std::function<void(Args...)>>::type f){
    // store f and call later
}
int main(){
    Callback<int, float>([](int a, float b){
        // do something
    });
}

Works like a charm.

Community
  • 1
  • 1
imer
  • 136
  • 1
  • 8
0

When the lambda is non-capturing, you could use:

template <typename L> void Callback(L l){
    using F = typename std::remove_pointer<decltype(+l)>::type;
    std::function<F> f( l );
    // store f and call later
}

which allows you to call:

Callback([](int a, float b){
    // do something
});

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180