Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to instantiate function templates which uses decltype to deduce return type, if called from inside a lambda?

I'm trying to use C++0x, and in particular lambda expression and decltype to simplify some of my code, using the MSVC10 RC compiler.

I've run into the following very odd problem:

template <typename F>
auto foo(F f) -> decltype(f()){
  return f();
}

template <typename F>
void bar(F f){
  f();
}

int main() {
  bar([](){
    foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
  });
}

As indicated in the comment, the compiler generates an error on the line foo([]() { }).

I hate to shout "compiler bug", but I really can't see any good explanation for this error. Apparently, while inside the outer lambda expression, the compiler can not specialize the foo function template for the inner lambda.

However, if the definition of foo is changed to hardcode the return type, like this:

template <typename F>
void foo(F f){
  return f();
}

then everything compiles just fine.

Is there some obscure quirk of decltype when used to deduce the return type of lambda expression parameters inside the scope of another lambda that I'm not aware of?

like image 692
jalf Avatar asked Feb 25 '10 16:02

jalf


1 Answers

These are just some test cases for people to observe.

Works

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

void dummy() {}

int main()
{
    auto x = []()
            {   // non-lambda parameter
                foo(dummy);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto f = [](){};
    auto x = [&]()
            {    // pre-defined lambda
                foo(f);
            };
}

Fails

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-argument lambda
                foo([]{});
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-scope lambda
                auto f = []{};
                foo(f);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-scope lambda, explicit return
                // (explicit return type fails too, `-> void`)
                auto f = [](){ return; };
                foo(f);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-argument lambda, explicit return non-void
                // (explicit return type fails too, `-> int`)
                foo([]{ return 5; }); 
            };
}

So it does seem to have to do with scope and the void type of the internal lambda, even when made explicit.(?)

like image 152
5 revs, 2 users 92% Avatar answered Sep 27 '22 19:09

5 revs, 2 users 92%