使用全局命名空间限定符和指向数据成员的指针

时间:2017-11-20 13:59:01

标签: c++ pointers

在结构中包含全局命名空间限定符时,尝试使用pointer to data member时遇到编译错误。我已将代码缩减为以下内容,正常工作

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)语言规范中有这个原因吗?

1 个答案:

答案 0 :(得分:37)

微妙的问题!

编译器不考虑额外的空格,因此您的代码实际上是:

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

......当然,这没有意义。你需要用括号消除歧义:

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

......一切都很好。

如果你没有括号,@Paula_plus_plus你有一个虚拟属性,实际上是空的,@T.C.帮助指出:

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

编译器需要以静默方式忽略它,但它确实解决了解析器的问题。