Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using global namespace qualifiers with pointer to data members

Tags:

c++

pointers

I'm experiencing a compile error when attempting to use a pointer to data member when including the global namespace qualifier on the struct. I've reduced my code to the following, which works:

namespace foo {
  using sausage = int;
  struct bar { sausage baz; };
}

auto chuckle(foo::bar barry, ::foo::sausage foo::bar::*paul) {
  return barry.*paul;
}

int main() {
  return chuckle(foo::bar{5}, &foo::bar::baz);
}

If I now add the global namespace qualifier to the bar struct in the argument to chuckle:

auto chuckle(foo::bar barry, ::foo::sausage ::foo::bar::*paul) {
                                        //  ^~ added ::
  return barry.*paul;
}

...then it no longer compiles and fails with the following error:

10 : <source>:10:37: error: 'foo::sausage' is not a class, namespace, or enumeration
 auto chuckle(foo::bar barry, ::foo::sausage ::foo::bar::*paul) {
                                     ^~~~~~~
10 : <source>:10:57: error: expected identifier before '*' token
 auto chuckle(foo::bar barry, ::foo::sausage ::foo::bar::*paul) {
                                                         ^
<source>: In function 'auto chuckle(foo::bar, int*)':
11 : <source>:11:17: error: 'paul' cannot be used as a member pointer, since it is of type 'int*'
   return barry.*paul;
                 ^~~~
<source>: In function 'int main()':
15 : <source>:15:45: error: cannot convert 'foo::sausage foo::bar::* {aka int foo::bar::*}' to 'int*' for argument '2' to 'auto chuckle(foo::bar, int*)'
   return chuckle(foo::bar{5}, &foo::bar::baz);
                                             ^

I see this behaviour across MSVC, Clang and GCC.

I've put both examples on Godbolt:

  • working example
  • failing example

Questions

a) Why does adding the global namespace qualifier cause the compilation to fail?

b) Is there a reason for this in the language specification?

like image 433
Rezzie Avatar asked Nov 20 '17 13:11

Rezzie


1 Answers

Subtle issue!

The compiler does not consider extra whitespace, so your code is actually:

auto chuckle(foo::bar barry, ::foo::sausage::foo::bar::*paul)

... which, of course, does not make sense. You need to disambiguate with parentheses:

auto chuckle(foo::bar barry, ::foo::sausage (::foo::bar::*paul))
//                                          ^                 ^

... and everything is fine.

If you're not into parentheses, @Paula_plus_plus has you covered with a dummy attribute, which can actually be empty as @T.C. helpfully points out:

auto chuckle(foo::bar barry, ::foo::sausage [[]] ::foo::bar::*paul)
//                                          ^^^^

The compiler is required to ignore it silently, but it does solve the problem for the parser.

like image 90
Quentin Avatar answered Nov 19 '22 11:11

Quentin