GCC doesn’t compile this code, while other compilers (clang, msvc) do
template<auto T>
struct S { };
int main() {
S<[]{int x,y; x<<y;}> s1; // compiles fine
S<[]{int x,y; x>>y;}> s2; // error
}
error:
error: expected ';' before '>>' token
| S<[]{int x,y; x>>y;}> s2;
| ^~
| ;
However when I explicitly call operator>>, GCC accepts it
struct S2 {
void operator>>(S2 arg) { }
};
S<[]{S2 x,y; x.operator>>(y);}> s2; // compiles
It also does compile when I move the lambda definition outside of template parameter list
auto lam = []{int x,y; x>>y;};
S<lam> s; // compiles
Is it a compiler bug?
>Solution :
g++ is actually correct here. From [temp.names]/3 (C++20 Draft N4860):
When a name is considered to be a template-name, and it is followed by a <, the < is always taken as the
delimiter of a template-argument-list and never as the less-than operator. When parsing a template-argumentlist,
the first non-nested > is taken as the ending delimiter rather than a greater-than operator. Similarly,
the first non-nested >> is treated as two consecutive but distinct > tokens, the first of which is taken as the
end of the template-argument-list and completes the template-id. [Note: The second > token produced by this
replacement rule may terminate an enclosing template-id construct or it may be part of a different construct
(e.g., a cast). —end note] [Example:
template class X { /* … / };
X< 1>2 > x1; // syntax error
X<(1>2)> x2; // OKtemplate class Y { / … */ };
Y<X<1>> x3; // OK, same as Y<X<1> > x3;
Y<X<6>>1>> x4; // syntax error
Y<X<(6>>1)>> x5; // OK
—end example]
The >> is treated as two > tokens. You can wrap it in brackets to enforce what you are trying to do if you want.
template<auto T>
struct S { };
int main() {
S<[]{int x,y; (x>>y);}> s2; // now compiles fine
}