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

时间:2015-04-01 13:34:43

标签: c++ templates c++11 initializer pointer-to-member

在工作中,我正在尝试一些来为我们的代码库带来一些反思。基本上我想要实现的是捕获数据成员初始化程序类型中的数据成员指针:

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

class Foo
{
public:
  int bar = Reflect<Foo, &Foo::bar>{};
};

尽管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. 如果是,是否有任何解决失败的编译器的工作?

1 个答案:

答案 0 :(得分:2)

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

  

名称的声明点在完成后立即生效   声明者(第8条)并在其初始化器之前(如果有的话),除了   如下所述。[...]

     

在成员声明之后,成员名称可以   在同班的范围内查阅。

这意味着名称查找很好。但是,正如@hvd在评论中指出的那样,这种结构的语法中存在某些含糊之处 据推测,GCC解析上述行直到逗号:

int bar = Reflect<Foo,
// at this point Reflect < Foo can be a perfectly fine relational-expression.
// stuff after the comma could be a declarator for a second member.

一旦遇到其他问题就罢免。

<小时/> 使GCC满意的解决方法是

    int bar = decltype( Reflect<Foo, &Foo::bar>{} )();

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

int bar;

Foo() : bar( Reflect<Foo, &Foo::bar>{} ) {}
// (also works for GCC)

...虽然在bar的声明中提供初始化器不能。 rextester Demo #2