内联成员初始化程序包含指向成员的指针

Eri*_*ing 7 c++ templates initializer pointer-to-member c++11

在工作中,我正在尝试一些,以反映我们的代码库.基本上我想要实现的是捕获数据成员的初始化器类型中的数据成员的指针:

template<class Class, int Class::*dataMember>
struct Reflect
{
  operator int() {return 0;}
};

class Foo
{
public:
  int bar = Reflect<Foo, &Foo::bar>{};
};
Run Code Online (Sandbox Code Playgroud)

虽然clang 3.4.1(http://gcc.godbolt.org/)和Intel C++ XE 14.0能够编译这段代码,但在使用MSVC12时,我收到以下错误消息:

错误C2065:'bar':未声明的标识符

错误C2975:'dataMember':'Reflect'的模板参数无效,是预期的编译时常量表达式

此外,gcc 4.9.2似乎也有问题:http://ideone.com/ZUVOMO.

所以我的问题是:

  1. 上面的代码是有效的C++ 11吗?
  2. 如果是,那么失败的编译器是否有任何解决方法?

Col*_*mbo 2

VC++所抱怨的当然不是问题;[basic.scope.pdecl]/1,6:

\n\n
\n

名称的声明点紧接在其完整声明符(第 8 条)之后和其初始值设定项(如果有)之前,除非下面注明。[\xe2\x80\xa6]

\n\n

在类成员声明点之后,可以在其类的范围内查找成员名称。

\n
\n\n

这意味着名称查找没问题。然而,正如 @hvd 在评论中指出的那样,此类结构的语法存在某些歧义。
\n大概 GCC 解析上面的行直到逗号:

\n\n
int bar = Reflect<Foo,\n// at this point Reflect < Foo can be a perfectly fine relational-expression.\n// stuff after the comma could be a declarator for a second member.\n
Run Code Online (Sandbox Code Playgroud)\n\n

一旦遇到其余的,就退出。

\n\n


\n让 GCC 满意的解决方法是

\n\n

    int bar = decltype( Reflect<Foo, &Foo::bar>{} )();\n
Run Code Online (Sandbox Code Playgroud)\n\n

演示。但这对 VC++ 没有帮助,这显然混淆了错误消息所指示的声明点。\n因此将初始值设定项移动到构造函数中将起作用:

\n\n
int bar;\n\nFoo() : bar( Reflect<Foo, &Foo::bar>{} ) {}\n// (also works for GCC)\n
Run Code Online (Sandbox Code Playgroud)\n\n

...同时在 can 的声明中提供初始值设定项bar。rextester 上的演示#2 。

\n