Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Right bit shift in body of lambda used as a template argument doesn't compile on GCC

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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; // OK

template 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
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading