Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a type deduction error for a lambda returning lambda with multiple return paths?

I have the following code:

int main() {
    auto f = [] {
        if (1) return [] { return 1; };
        else return [] { return 2; };
    };
    return f()();
}

which raises the following compiler error using GCC 5.2.1:

error: inconsistent types ‘main()::<lambda()>::<lambda()>’ and 
       ‘main()::<lambda()>::<lambda()>’ deduced for lambda 
       return type else return [] { return 2; };

Now obviously those two types look to be the same, so I'm not sure if this is GCC with a misleading error message or if it's actually a bug. According to my knowledge this should compile; the lambda return type should be deduced to be std::function<int()>. Interestingly, if I pre-declare the lambda return and return the same variable twice, it works.

Can anyone shed some light as to what is happening? I found similar looking questions, many attributed to GCC bugs, but this looks different.

like image 485
Alex Avatar asked Jan 08 '16 00:01

Alex


People also ask

What is the return type of lambda function?

The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.

Does lambda expression must always have a return type?

Using Lambda ExpressionsThe lambda expression should have the same number of parameters and the same return type as that method.

What is the return type of lambda expression in Java 8?

The return type of a method in which lambda expression used in a return statement must be a functional interface.

What is the type of a lambda expression C++?

2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5. 1).


2 Answers

Now obviously those two types are the same,

No, they're not. The type of every lambda expression is a unique, distinct type.

From [expr.prim.lambda]/3:

The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below.

Therefore, return type deduction for f fails and does not result in std::function<int()>. The latter is an unrelated library type that isn't somehow magically the "common type" of any closure type.

Of course each of the unique closure types can be converted to std::function<int()>, so if you provide the return type, everything works:

auto f = []() -> std::function<int()> {
    return 1 ? []() { return 1; }
             : []() { return 2; };
};

Or, as a plain function:

std::function<int()> f() {
    return 1 ? []() { return 1; }
             : []() { return 2; };
}
like image 88
Kerrek SB Avatar answered Sep 20 '22 13:09

Kerrek SB


Every lambda has its own, unique type:

The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type[...].

From here, emphasize mine.

Also, lambdas have nothing to do with std::function, that is another different type. In particular,

[] { return 1; }

and

[] { return 2; }

have different types. This is why deduction fails.

like image 43
Baum mit Augen Avatar answered Sep 20 '22 13:09

Baum mit Augen