42

Issue: passing a generic lambda (to a template function) that captures this and calls a member function of this without an explicit this-> does not compile on gcc. If the lambda is not generic, or if the lambda is not passed to any other function but called in place, it compiles withoit an explicit this->. Clang is cool with the code in all situations.

Time for another round of clang vs gcc. Who's right?

Wandbox example


template<typename TF>
void call(TF&& f)
{
    f(1);   
}

struct Example
{        
    void foo(int){ }

    void bar()
    {
        call([this](auto x){ foo(x); });
    }
};

int main()
{
    Example{}.bar();
    return 0;
}

  • With bar() = call([this](auto x){ foo(x); });
    • clang++ 3.6+ compiles.
    • g++ 5.2+ does not compile.

      error: cannot call member function 'void Example::foo(int)' without object call([this](auto x){ foo(x); });`


  • With bar() = call([this](auto x){ this->foo(x); });
    • clang++ 3.6+ compiles.
    • g++ 5.2+ compiles.

  • With bar() = call([this](int x){ foo(x); });
    • clang++ 3.6+ compiles.
    • g++ 5.2+ compiles.

  • With bar() = [this](auto x){ foo(x); }(1);
    • clang++ 3.6+ compiles.
    • g++ 5.2+ compiles.

Why is the this-> necessary only in the case of a generic lambda?

Why is the this-> not necessary if the lambda isn't passed to call?

Who is being non standard-compliant?

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 3
    The inconsistencies you note indicate that clang is correct here. – Cheers and hth. - Alf Aug 19 '15 at 14:07
  • 8
    Without even looking at the standard, I can say with absolute certainty that Clang is right. Even if it disagrees with the standard, it's still right; in that case the standard is wrong. GCC's behavior makes absolutely no sense whatsoever. – Sebastian Redl Aug 19 '15 at 14:07
  • 2
    [related but not a dupe?](http://stackoverflow.com/q/20312062/819272) – TemplateRex Aug 19 '15 at 14:07
  • @Cheers, SebastianRedl: you're probably right. I'm reporting this on the gcc bug tracker. – Vittorio Romeo Aug 19 '15 at 14:09
  • 1
    [another related Q&A](http://stackoverflow.com/q/31673204/819272) – TemplateRex Aug 19 '15 at 14:10
  • 2
    Reported the bug [67274](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67274). – Vittorio Romeo Aug 19 '15 at 14:14
  • 2
    MSVC Community 2015 RC V14.0.22823.1 Will compile all cases as well – NathanOliver Aug 19 '15 at 14:14
  • 1
    the gcc 5 series is not yet ready for prime time it seems, especially with exotic combinations of C++14 features (generic lambdas, relaxed constexpr). My rough feeling is that 5.1 / 5.2 are to C++14 what 4.6 and 4.7 were to C++11 (i.e. significantly less bug-free than the later 4.8 and .49) – TemplateRex Aug 19 '15 at 14:16
  • I just hit this with a patch to LLVM: https://reviews.llvm.org/D78849, https://reviews.llvm.org/D78962. Playing with your example in godbolt, it looks like this is fixed in g++-7.1 release. – Nick Desaulniers Apr 27 '20 at 20:12

1 Answers1

18

This is a gcc bug. From [expr.prim.lambda]:

The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression. [ Example:

struct S1 {
    int x, y;
    int operator()(int);
    void f() {
        [=]()->int {
            return operator()(this->x + y); 
                // equivalent to S1::operator()(this->x + (*this).y)
                // this has type S1*
        };
    }
};

—end example ]

Since in your example you capture this, the name lookup should include class members of Example, which should therefore find Example::foo. The lookup performed is identical to what would happen if foo(x) appeared in the context of the lambda-expression itself, that is if the code looked like:

void bar()
{
    foo(x); // clearly Example::foo(x);
}

At least this bug has a very simple workaround as indicated in the question: just do this->foo(x);.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Is there an upstream bug report to track this? – jotik Apr 19 '16 at 12:53
  • @jotik Yeah, OP [reported it](http://stackoverflow.com/questions/32097759/calling-this-member-function-from-generic-lambda-clang-vs-gcc/32098850#comment52090459_32097759). – Barry Apr 19 '16 at 15:15