Bug 54557 - [c++ lambda] error in assigning lambda expr though "operator?:" while capturing
Summary: [c++ lambda] error in assigning lambda expr though "operator?:" while capturing
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-09-12 11:29 UTC by vincenzo Innocente
Modified: 2012-09-13 06:37 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description vincenzo Innocente 2012-09-12 11:29:10 UTC
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)
Comment 1 Daniel Krügler 2012-09-12 20:54:26 UTC
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.
Comment 2 vincenzo Innocente 2012-09-13 06:37:02 UTC
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.