in this example foo1 and foo2 do not compile, bar and foo3 do. cat iflamda.cc struct A { int q; bool sel; bool bar(int i, int j) const; bool foo1(int i, int j) const; bool foo2(int i, int j) const; bool foo3(int i, int j) const; }; bool A:: bar(int i, int j) const { auto f = sel ? [](int a, int b) { return a<b;} : [](int a, int b) { return b<a;}; return f(i,j); } bool A::foo1(int i, int j) const { auto f = sel ? [this](int a, int b) { return a<b;} : [this](int a, int b) { return a<b+this->q;}; return f(i,j); } bool A::foo2(int i, int j) const { int k = q; auto f = sel ? [k](int a, int b) { return a<b;} : [k](int a, int b) { return a<b+k;}; return f(i,j); } bool A::foo3(int i, int j) const { auto f = sel ? [](int a, int b,int) { return a<b;} : [](int a, int b, int k) { return a<b+k;}; return f(i,j,q); } Vincenzos-MacBook-Pro:ctest innocent$ c++ -O2 -std=gnu++11 -c iflamda.cc iflamda.cc: In member function ‘bool A::foo1(int, int) const’: iflamda.cc:24:60: error: no match for ternary ‘operator?:’ (operand types are ‘bool’, ‘A::foo1(int, int) const::__lambda2’, and ‘A::foo1(int, int) const::__lambda3’) [this](int a, int b) { return a<b+this->q;}; ^ iflamda.cc: In member function ‘bool A::foo2(int, int) const’: iflamda.cc:33:51: error: no match for ternary ‘operator?:’ (operand types are ‘bool’, ‘A::foo2(int, int) const::__lambda4’, and ‘A::foo2(int, int) const::__lambda5’) [k](int a, int b) { return a<b+k;}; ^ Vincenzos-MacBook-Pro:ctest innocent$ c++ -v Using built-in specs. COLLECT_GCC=c++ COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-apple-darwin12.1.0/4.8.0/lto-wrapper Target: x86_64-apple-darwin12.1.0 Configured with: ./configure --enable-languages=c,c++,fortran --disable-multilib --disable-bootstrap --enable-lto -disable-libitm Thread model: posix gcc version 4.8.0 20120912 (experimental) [trunk revision 191215] (GCC)
The compiler behaviour looks correct to me. The difference of the lambda expressions in bar and foo3 compared to the other two is that these are capture-free lambdas and thus have a conversion function to function pointer. Each lambda expression corresponds to a unique class type, so what we have in foo1 and foo2 can be compared with the following class-example: struct A{}; struct B{}; void f() { false ? A() : B(); } This expression has no common type for the conditional operator and is ill-formed. What we have in bar and foo3 can be compared with the following class-example : struct A{ typedef void (*F)(); operator F(); }; struct B{ typedef void (*F)(); operator F(); }; void f() { false ? A() : B(); } This is well-formed, because in the last step of the conditional operator conversion attempts (5.16p5), more general conversions are attempted and these find the common pointer to function. The current compiler behaviour gives a correct diagnostics and I see nothing wrong with it.
Understood. Thanks for the detailed answer: I will read the standard more in detail. Syntactic-wise It seems that I can implement it as bool A::foo4(int i, int j) const { auto f1 = sel ? [](int a, int b,int) { return a<b;} : [](int a, int b, int k) { return a<b+k;}; auto f = [this,f1](int a, int b) { return f1(a,b,q);}; return f(i,j); } As optimization is what I'm looking for I will look to the generated assembler and then decide the specific implementation.