Подтвердить что ты не робот

Использование глобальных классификаторов пространства имен с указателем на элементы данных

У меня возникает ошибка компиляции при попытке использовать указатель для члена данных при включении классификатора пространства имен в структуру. Я сократил свой код до следующего, который работает:

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);
}

Если я теперь добавлю глобальный определитель пространства имен в структуру bar в аргументе chuckle:

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

... то он больше не компилируется и не работает со следующей ошибкой:

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);
                                             ^

Я вижу это поведение в MSVC, Clang и GCC.

Я привел оба примера на Godbolt:

Вопросы

a) Почему добавление глобального классификатора пространства имен приводит к сбою компиляции?

b) Есть ли причина для этого в спецификации языка?

4b9b3361

Ответ 1

Тонкая проблема!

Компилятор не рассматривает лишние пробелы, поэтому ваш код на самом деле:

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

... что, конечно, не имеет смысла. Вам нужно устранить двусмысленность с помощью круглых скобок:

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

... и все в порядке.

Если вы не находитесь в круглых скобках, @PaperBirdMaster вы покрыли фиктивный атрибут:

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

Компилятор должен игнорировать его молча, но он решает проблему для синтаксического анализатора.