11

I cannot compile the following program with gcc 6.1:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

class Foo
{
public:
    void apply() const
    {
        std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { print(x); });
    }
private:
    std::vector<std::string> bars_;

    void print(const std::string& x) const
    {
        std::cout << x << ' ';
    }
};

int main()
{
    Foo foo {};
    foo.apply();
    return 0;
}

The error message is:

error: cannot call member function 'void Foo::print(const string&) const' without object
         std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { print(x); });
                                                                                      ^~~~~
  • Changing const auto& x to const std::string& x makes the program compile.

  • Changing print(x) to this->print(x) makes the program compile.

  • All versions compile with Clang (Apple LLVM version 7.3.0 (clang-703.0.31)).

Is this a compiler bug?

Daniel
  • 8,179
  • 6
  • 31
  • 56
  • Couldn't this be because a generic lambda is just a `template` function pretending not to be a `template` function, and you must qualify `this->` similarly in real template functions too? IIRC... – underscore_d Aug 09 '16 at 08:48
  • 2
    @underscore_d That's for dependent bases. – T.C. Aug 09 '16 at 08:49
  • 5
    clang compiles it, maybe its gcc bug, see here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636 – marcinj Aug 09 '16 at 08:52

3 Answers3

5

This is a documented gcc bug which as of August 2016 has not been fixed yet.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
-3

I don't think the compiler is obliged to deduce the type being passed to the lambda inside the for_each function, bear in mind this function has already been compiled, how can the compiler know what the for_each function is going to pass to the lambda after it passed the lambda in?

Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
1stCLord
  • 860
  • 5
  • 14
  • Well, it hasn't been compiled, because there's an error that blocks compilation. But I see what you're getting at. As the 3rd argument can be any callable, it seemed to me and I think you that its argument could be deducible from the input iterators, but the rest of its type couldn't. However, that just seems to be a limitation in our understanding, because `clang` accepts it, and the linked Bugzilla implies it's a valid case suffering from ambiguity in the `g++` parser. – underscore_d Aug 09 '16 at 08:53
  • Sorry, I meant the for_each function has already been compiled. – 1stCLord Aug 09 '16 at 08:55
  • 1
    It certainly looks like a bug, the error error: cannot call member function 'void Foo::print(const string&) const' without object implies it correctly deduced the parameter type – 1stCLord Aug 09 '16 at 08:57
  • 2
    The compiler instantiates the `for_each` with the given template parameter, which then causes instantiation of the lambda with the correct type. – interjay Aug 09 '16 at 09:02
  • @interjay OMG OFC it does, how could I have forgotten/not noticed for_each is a template function! Thanks. – 1stCLord Aug 09 '16 at 09:39
-4

I don't know why. But the solution is to specify which print it should use: std::for_each(std::cbegin(bars_), std::cend(bars_), [this] (const auto& x) { this->print(x); });

With this it compiles. See: http://coliru.stacked-crooked.com/a/1177b09a3e5863e2

frank
  • 147
  • 6
  • 3
    This is not an answer. The question already explicitly states that adding `this->` makes this compile. – lisyarus Aug 09 '16 at 11:13
  • than look at http://stackoverflow.com/questions/11284059/call-method-inside-lambda-expression or http://stackoverflow.com/questions/4940259/lambdas-require-capturing-this-to-call-static-member-function – frank Aug 09 '16 at 11:14
  • 3
    This is still irrelevant. The code in the question already explicitly captures `this`. – lisyarus Aug 09 '16 at 11:15