在结构中包含全局命名空间限定符时,尝试使用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)语言规范中有这个原因吗?
答案 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)
// ^^^^
编译器需要以静默方式忽略它,但它确实解决了解析器的问题。