Function name resolution in a lambda that captures

2019-07-07 02:27发布

I'm looking at the following code:

#include <iostream>

void f()
{
    std::cout << "Called ::f()" << std::endl;
}

struct S
{
    void f()
    {
        std::cout << "Called S::f()" << std::endl;
    }

    void oops()
    {
        [this](){ f(); }(); // calls the wrong function
    }
};

int main()
{
    S().oops();
    return 0;
}

(http://ideone.com/w7nyb)

VS2010 calls ::f() but GCC & VS2012 calls S::f(). To me it seems that VS2012 is correct.

Which function should be called according to the standard?

1条回答
贼婆χ
2楼-- · 2019-07-07 03:17

S::f() should be called. C++11 §5.1.2/7 states:

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

The important part here is that "for purposes of name lookup,... the compound-statement is considered in the context of the lambda-expression." Since there is no f declared locally in the lambda block, it is looked up just as it would be looked up if it was referred to directly from the body of oops. Therefore, the member function is found.


Note that recent versions of Visual C++ and gcc both have the correct behavior (including Visual C++ 2012 and gcc 4.7.2). Older versions may exhibit incorrect behavior because the lambda specification was overhauled in the second half of 2009 (see n2927: New wording for C++0x Lambdas [PDF]). Remember that before C++11 was finalized, the specification was a moving target, and older compilers are likely to implement different revisions of the specification. Even now, many implementers are still working to catch up to the final specification.

查看更多
登录 后发表回答