48
#include <iostream>

void IsTrue(const bool value) {
  if (value) {
    std::cout << "value is True!\n";
  }
}

int main()
{
  IsTrue([]() { ; /* some lambda */ });

  return 0;
}

Output:

value is True!

Why does the lambda evaluate to true on GCC & Clang? MSVC cannot build this (cannot convert lambda to bool).

Is it a compiler bug? Or which paragraph of the standard allows this?

Boann
  • 48,794
  • 16
  • 117
  • 146
vladon
  • 8,158
  • 2
  • 47
  • 91
  • 12
    Not sure if this is legal or not but it appears to be converting the lambda into a function pointer and then using that value (which is not null) into the bool so it compiles. If you add a capture [it fails to compile](http://coliru.stacked-crooked.com/a/f28beac0173e86e4). – NathanOliver Jan 18 '17 at 13:46
  • 8
    MSVC has [a nonstandard extension](https://adishavit.github.io/2016/magical-captureless-lambdas/), so it requires you to explicitly spell out the destination function pointer type, otherwise the conversion will fail. – cpplearner Jan 18 '17 at 14:03
  • Also see [Passing lambda as function pointer](http://stackoverflow.com/q/28746744/1708801) – Shafik Yaghmour Jan 18 '17 at 21:25
  • @NathanOliver yes it is legal see [\[conv.bool\]](http://eel.is/c++draft/conv.bool) – Shafik Yaghmour Jan 18 '17 at 21:42

1 Answers1

46

The C++14 standard (§5.1.2) says:

The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

Since a function pointer is implicitly convertible to bool, you get the result you have shown. This is perfectly legal.

MSVC doesn't compile this because this conversion operator is overloaded with different calling conventions (__stdcall, __cdecl, etc). When compiling for x64 all those calling conventions are not used, so there's just one conversion operator and it compiles fine.

DeiDei
  • 10,205
  • 6
  • 55
  • 80