ttsiodras
ttsiodras

Reputation: 11268

C++0x and lambdas

Look at this template:

template <class T>
auto checkErrorCode(T& functor) -> decltype(functor()) {
    auto retCode = functor();
    // ... additional aspect-like stuff with retCode here
    return retCode;
}

It is supposed to execute a lambda passed inside it, get the return value from the lambda, do something with it, and then return it back to the caller. Think "aspect programming", logging, whatever.

Even though it compiles and works fine with this...

int foo(int param)
{
    return param>10?0:-1;
}

main()
{
    int param = 11;

    // This compiles fine
    auto action = [&](){ return foo(param); };
    checkErrorCode( action );
}

...it doesn't compile - and emits a hard to understand error - when I directly call "checkErrorCode" with an inline lambda:

int foo(int param)
{
    return param>10?0:-1;
}

main()
{
    int param = 11;

    // This doesn't compile...
    checkErrorCode( [&](){ return foo(param); } );
}

Any thoughts as to why?

g++ emits this weird error:

forSO.cpp: In function 'int main()':
forSO.cpp:24:5: error: no matching function for call to 'checkErrorCode(main()::<lambda()>)'
forSO.cpp:24:5: note: candidate is:
forSO.cpp:2:6: note: decltype (functor()) checkErrorCode(T&) [with T = main()::<lambda()>, decltype (functor()) = int]
forSO.cpp:2:6: note:   no known conversion for argument 1 from 'main()::<lambda()>' to 'main()::<lambda()>&'

In the unlikely case that this is a compiler bug:

bash$ g++ -v
...
gcc version 4.6.2 (GCC) 

Upvotes: 2

Views: 559

Answers (1)

moshbear
moshbear

Reputation: 3322

The template needs to use an rvalue reference:

template <class T>
auto checkErrorCode(T&& functor) -> decltype(functor()) {
    auto retCode = functor();
    // ... additional aspect-like stuff with retCode here
    return retCode;
}

Or, const lvalue (const T&). Because lambdas are temporary (rvalue) functions, you can only pass them by const (lvalue) reference or by rvalue reference.

As a rule, keep lvalue refs const unless you plan to do non-const accesses (e.g. left side of assignment, call of non-const member function, etc.) If you're doing continuations, it can get a bit more complicated because then you have to pass a non-const lvalue reference. But you'd have an explicit functor class, so non-const lvalue ref creation is allowed. In this case, it's clearer to use a rvalue ref for lambdas, as const lvalue ref is the C++98 way of doing things, and limitations of that system were a motivating factor for creating rvalue references.

Upvotes: 4

Related Questions