如果与通用lambda结合使用,std :: list :: remove_if会变得疯狂

sky*_*ack 12 lambda gcc clang language-lawyer c++14

我发现一个问题,我猜是由于GCC中的一个错误.
无论如何,在开启问题之前,我想确定一下.

请考虑以下代码:

#include<algorithm>
#include<list>

template<typename U>
struct S {
    using FT = void(*)(); 
    struct T { FT func; };

    template<typename> 
    static void f() { } 

    std::list<T> l{ { &f<int> }, { &f<char> } };

    void run() {  
        l.remove_if([](const T &t) { return t.func == &f<int>; }); // (1)
        l.remove_if([](const auto &t) { return t.func == &f<int>; }); // (2)
    }
};

int main() {
    S<void> s;
    s.run();
}
Run Code Online (Sandbox Code Playgroud)

clang v3.9 按预期编译(1)(2).
GCC v6.2 编译(1),但它不编译(2).
返回的错误是:

错误:未在此范围内声明'f'

此外,请注意GCC 编译(2)如果修改如下:

l.remove_if([](const auto &t) { return t.func == &S<U>::f<int>; }); // (2)
Run Code Online (Sandbox Code Playgroud)

据我所知,在这种情况下使用an const auto &而不是const T &不应改变行为.

这是GCC的错误吗?

eca*_*mur 8

Per [expr.prim.lambda]:

8 - [...] [For]名称查找(3.4)[...]复合语句在lambda表达式的上下文中被考虑.[...]

MCVE:

template<int>
struct S {
  template<int> static void f();
  S() { void(*g)(char) = [](auto) { f<0>; }; }
};
S<0> s;
Run Code Online (Sandbox Code Playgroud)

将复合语句挂起到lambda表达式的上下文会给出一个明确有效的程序:

template<int>
struct S {
  template<int> static void f();
  S() { f<0>; }
};
S<0> s;
Run Code Online (Sandbox Code Playgroud)

所以,是的,这是gcc中的一个错误.