用作模板参数的 lambda 主体中的右位移位无法在 GCC 上编译

mic*_*huu 2 c++ gcc templates compiler-bug c++20

GCC 不会编译此代码,而其他编译器(clang、msvc)会编译此代码

template<auto T>
struct S { };

int main() {
  S<[]{int x,y; x<<y;}> s1; // compiles fine
  S<[]{int x,y; x>>y;}> s2; // error
}
Run Code Online (Sandbox Code Playgroud)

错误:

error: expected ';' before '>>' token
      |     S<[]{int x,y; x>>y;}> s2;
      |                    ^~
      |                    ;
Run Code Online (Sandbox Code Playgroud)

但是,当我明确调用时operator>>,GCC 接受它

struct S2 {
  void operator>>(S2 arg) { }
};
S<[]{S2 x,y; x.operator>>(y);}> s2; // compiles
Run Code Online (Sandbox Code Playgroud)

当我将 lambda 定义移到模板参数列表之外时,它也会进行编译

auto lam = []{int x,y; x>>y;}; 
S<lam> s; // compiles
Run Code Online (Sandbox Code Playgroud)

这是编译器错误吗?

Chr*_*sMM 6

g++ 这里实际上是正确的。来自[temp.names]/3C++20 草案 N4860):

\n
\n

当名称被认为是template-name且后跟 a 时<,始终被视为template-argument-list<的分隔符,而绝不会被视为小于运算符。解析template-argument-list时,第一个非嵌套的被视为结束分隔符而不是大于运算符。类似地,第一个非嵌套被视为两个连续但不同的标记,其中第一个被视为template-argument-list的末尾并完成template-id。[注意:此替换规则生成的第二个标记可能终止封闭的template-id构造,或者它可能是不同构造的一部分(例如,强制转换)。\xe2\x80\x94 尾注] [示例>>>>>

\n
template<int i> class X { /* ... */ };\nX< 1>2 > x1;                            // syntax error\nX<(1>2)> x2;                            // OK\n\ntemplate<class T> class Y { /* ... */ };\nY<X<1>> x3;                             // OK, same as Y<X<1> > x3;\nY<X<6>>1>> x4;                          // syntax error\nY<X<(6>>1)>> x5;                        // OK\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x94结束示例]

\n
\n

>>视为两个>令牌。如果您愿意,您可以将其括在括号中以强制执行您想要执行的操作。

\n
template<auto T>\nstruct S { };\n\nint main() {\n  S<[]{int x,y; (x>>y);}> s2; // now compiles fine\n}\n
Run Code Online (Sandbox Code Playgroud)\n

注意:接受或拒绝可能都是正确的,因为嵌套的含义有点模糊。看评论。

\n