我在Windows上面对“错误C2327”。
我减less了我的代码,并得到与testing程序类似的错误
#include <boost/intrusive/list.hpp> #include <iostream> class Test { protected: typedef Test self_type; boost::intrusive::list_member_hook<> order_hook; public: typedef boost::intrusive::member_hook<self_type, boost::intrusive::list_member_hook<>, & Test::order_hook > order_hook_type; };
这工作正常在g ++,但在Windows提供以下错误:
test.cpp(11) : error C2327: 'Test::order_hook' : is not a type name, static, or enumerator test.cpp(11) : error C2065: 'order_hook' : undeclared identifier
请帮忙。 我失踪的窗户?
tl; dr:Visual Studio是正确的 – 你不能把那个typedef
放在那里。
Boost文档正确,但不能解释为什么 。
[C++11: 14.3.2/1]:
非模板非模板模板参数的模板参数应该是以下之一:
- 对于整型或枚举类型的非类型模板参数 , 模板参数类型的转换后的常量表达式(5.19) 要么
- 非类型模板参数的名称 ; 要么
- 一个常量表达式(5.19),指定具有静态存储持续时间和外部或内部链接的对象的地址,或者具有外部或内部链接的函数,包括函数模板和函数模板id,但不包括非静态类成员,括号)作为
& id-expression
,除了如果名称引用函数或数组,则可以省略&,如果相应的模板参数是引用,则省略& 要么- 一个常量表达式,其值为空指针值(4.10); 要么
- 一个常量表达式,其值为空成员指针值(4.11); 要么
- 一个指向成员的指针,如5.3.1所述 。
[C++11: 5.3.1/3]:
一元&
运算符的结果是一个指向其操作数的指针。 操作数应该是一个左值或者是一个合格的id 。 如果操作数是一个qualified-id,它命名类型为T
的某个类C
的非静态成员m
,则结果的类型为“指向类型为T
的类C
的成员”,并且是一个指定C::m
。 [..]
[C++11: 8.3.3/2]
给出了一个不完整类型的成员指针的例子,只要指向成员的指针没有被初始化,它就是有效的,虽然没有明确说明,这意味着要实际取一些C::m
的地址, C
必须是完整的类型。 的确,直到C
是一个完整的类型, C::m
并不存在。
有一些类似的规则更清晰:
[C++11: 9.2/10]
:非静态(9.4)数据成员不应该有不完整的类型。 特别是,C
类不能包含C
类的非静态成员,但它可以包含一个指向C
类对象的指针或引用。
在你的typedef
, Test
不是一个完整的类型:
[C++11: 9.2/2]:
类被认为是一个完全定义的对象类型(3.9)(或完整类型),在类的说明符的结尾处。 在类成员规范中 ,对于非静态数据成员(包括嵌套类中的这些内容),该类在函数体,缺省参数, 异常说明以及括号或等同初始值设定项中被认为是完整的。 否则,在其自己的类成员规范中被认为是不完整的。
因此,你不能在那个地方使用指向成员的指针。 您必须编写typedef
,使其在类定义的关闭}
之后出现,或者使指向对象非成员或static
成员。
GCC 在这方面必须有一个错误或扩展 ,因为下面的测试用例编译和执行成功:
template <typename B, int B::* PTM> struct A {}; struct B { int x; typedef A<B, &B::x> a; }; int main() { B b; }
而Visual Studio 2012 Express正确输出:
1> ——开始生成:Project:test1,Configuration:Debug Win32 ——
1> test.cpp
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2327:'B :: x':不是类型名称,静态或枚举数
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2065:'x':未声明的标识符
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2975:'PTM':无效的模板参数为'A',预期的编译时常量表达式
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(1):参见“PTM”
==========构建:0成功,1失败,0最新,0跳过==========
tl; dr:Visual Studio有一个错误:你的代码是合法的。
[C++11: 14.3.2/1]:
一个非类型的非模板模板参数的模板参数应该是以下之一:
- 对于整型或枚举类型的非类型模板参数 , 模板参数类型的转换后的常量表达式(5.19) 要么
- 非类型模板参数的名称 ; 要么
- 一个常量表达式(5.19),指定具有静态存储持续时间和外部或内部链接的对象的地址,或者具有外部或内部链接的函数,包括函数模板和函数模板id,但不包括非静态类成员,括号)作为
& id-expression
,除了如果名称引用函数或数组,则可以省略&,如果相应的模板参数是引用,则省略& 要么- 一个常量表达式,其值为空指针值(4.10); 要么
- 一个常量表达式,其值为空成员指针值(4.11); 要么
- 一个指向成员的指针,如5.3.1所述 。
[C++11: 5.3.1/3]:
一元&
运算符的结果是一个指向其操作数的指针。 操作数应该是一个左值或者是一个合格的id 。 如果操作数是一个qualified-id,它命名类型为T
的某个类C
的非静态成员m
,则结果的类型为“指向类型为T
的类C
的成员”,并且是一个指定C::m
。 [..]
[C++11: 3.4.3.1/1]
:如果qualified-id的嵌套名称说明符指定了一个类,则在该类的范围内查找在嵌套名称说明符之后指定的名称 (10.2 ),下面列出的情况除外。 该名称应代表该类或其基类之一或多个成员(第10条)。 [注: 一个类成员可以在其潜在的范围内的任何一点使用一个合格的id (3.3.7) 。 – 注意] 上面的名称查找规则的例外情况如下:
- 按照3.4.3的规定查找析构函数的名字;
- 在类成员访问(见3.4.5)中,以与转换类型标识相同的方式查找conversion-function-id的conversion-type-id 。
- 在整个后缀表达式出现的上下文中查找模板ID的模板参数中的名称。
- 使用声明(7.3.3)中指定名称的查找也会查找隐藏在相同范围(3.3.10)内的类或枚举名称。
这里没有一个例外,所以我们看看类成员的“潜在作用域”:
[C++11: 3.3.7/1]:
以下规则描述了在类中声明的名称范围。
- 在类中声明的名称的潜在作用域不仅包括声明后的声明区域 ,而且还包括所有函数体,非静态数据成员的括号或等同初始值设定项,以及默认参数类(包括嵌套类中的东西)。
- [..]
GCC 正确编译并执行以下测试用例 :
template <typename B, int B::* PTM> struct A {}; struct B { int x; typedef A<B, &B::x> a; }; int main() { B b; }
而Visual Studio 2012 Express错误地出错:
1> ——开始生成:Project:test1,Configuration:Debug Win32 ——
1> test.cpp
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2327:'B :: x':不是类型名称,静态或枚举数
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2065:'x':未声明的标识符
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):error C2975:'PTM':无效的模板参数为'A',预期的编译时常量表达式
1> f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(1):参见“PTM”
==========构建:0成功,1失败,0最新,0跳过==========