错误C2327:不是类型名称,静态或枚举器

时间:2013-10-24 10:57:21

标签: c++ windows visual-studio templates g++

我在Windows上遇到“错误C2327” 我减少了我的代码,并在测试程序中得到了类似的错误

#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

请帮忙。我缺少什么窗户?

3 个答案:

答案 0 :(得分:4)

tl; dr:Visual Studio是对的 - 您无法将typedef放在那里。
Boost文档gets this right, but doesn't explain why


  

[C++11: 14.3.2/1]: 非类型非模板模板参数的 template-argument 应为之一:

     
      
  • 表示整数或枚举类型的非类型模板参数 template-parameter 类型的转换常量表达式(5.19);或
  •   
  • 非类型模板参数的名称;或
  •   
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数 template-ids 但排除非静态类成员,表示(忽略括号)为& id-expression,但如果名称引用函数或数组则可省略&,如果相应的模板则应省略-parameter 是一个参考;或
  •   
  • 一个求值为空指针值的常量表达式(4.10);或
  •   
  • 一个常量表达式,其值为null成员指针值(4.11);或
  •   
  • 指向成员的指针,如5.3.1
  • 中所述   
     

[C++11: 5.3.1/3]:一元&运算符的结果是指向其操作数的指针。操作数应为左值或 qualified-id 。如果操作数是 qualified-id ,则命名类型为m的某个类C的非静态成员T,结果的类型为“指向成员的指针属于C类的T类,并且是指定C::m的prvalue。 [..]

[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)(或完整类型)。在类 member-specification 中,该类在函数体,默认参数, exception-specifications brace-or-equal-initializers <中被视为完整的/ em>用于非静态数据成员(包括嵌套类中的此类内容)。 否则在其自己的类成员规范中被视为不完整。

因此,您无法在该位置使用该指针指向成员。您必须编写typedef以便在类定义的结束}之后显示,或使指向对象成为非成员或static成员。

GCC must have a bug or extension in this regard,因为以下测试用例编译并成功执行:

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&gt; ------ Build build:Project:test1,Configuration:Debug Win32 ------
  1 GT; TEST.CPP
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2327:'B :: x':不是类型名称,静态或枚举器
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2065:'x':未声明的标识符
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2975:'PTM':'A'的模板参数无效,预期的编译时常量表达式
  1 GT; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(1):见“PTM”声明
  ==========构建:0成功,1个失败,0个最新,0个跳过==========

答案 1 :(得分:3)

tl; dr:Visual Studio有一个错误:您的代码是合法的。


  

[C++11: 14.3.2/1]: 非类型非模板模板参数的 template-argument 应为之一:

     
      
  • 表示整数或枚举类型的非类型模板参数 template-parameter 类型的转换常量表达式(5.19);或
  •   
  • 非类型模板参数的名称;或
  •   
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数 template-ids 但排除非静态类成员,表示(忽略括号)为& id-expression,但如果名称引用函数或数组则可省略&,如果相应的模板则应省略-parameter 是一个参考;或
  •   
  • 一个求值为空指针值的常量表达式(4.10);或
  •   
  • 一个常量表达式,其值为null成员指针值(4.11);或
  •   
  • 指向成员的指针,如5.3.1
  • 中所述   
     

[C++11: 5.3.1/3]:一元&运算符的结果是指向其操作数的指针。 操作数应左值或 a qualified-id 。如果操作数是 qualified-id ,则命名类型为m的某个类C的非静态成员T,结果的类型为“指向成员的指针属于C类的T类,并且是指定C::m的prvalue。 [..]

     

[C++11: 3.4.3.1/1]:如果 qualified-id 嵌套名称说明符指定了一个类,则在嵌套名称后指定的名称除了下面列出的情况之外,在类(10.2)的范围内查找-specifier 。该名称应代表该类别或其基类之一的一个或多个成员(第10条)。 [注意: 一个班级成员   可以在其潜在范围(3.3.7)的任何一点使用 qualified-id 来引用。 -end note] 以上名称查找规则的例外情况如下:

     
      
  • 按3.4.3;
  • 中的规定查找析构函数名称   
  • conversion-function-id conversion-type-id 的查找方式与 conversion-type-id 在班级成员访问中(见3.4.5);
  •   
  • template-id template-argument 中的名称将在整个 postfix-expression 发生的上下文中查找
  •   
  • 查找using-declaration(7.3.3)中指定的名称还会查找隐藏在同一范围内的类或枚举名称(3.3.10)。
  •   

这里没有例外,所以我们看一下班级成员的“潜在范围”:

  

[C++11: 3.3.7/1]:以下规则描述了在类中声明的名称范围。

     
      
  1. 在类中声明的名称的潜在范围不仅包括名称的声明点后面的声明性区域,还包括所有函数体,非支撑或等于初始化器-static数据成员,以及该类中的默认参数(包括嵌套类中的这些内容)。
  2.   
  3. [..]
  4.   

GCC correctly compiles and executes the following testcase

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&gt; ------ Build build:Project:test1,Configuration:Debug Win32 ------
  1 GT; TEST.CPP
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2327:'B :: x':不是类型名称,静态或枚举器
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2065:'x':未声明的标识符
  1&gt; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(8):错误C2975:'PTM':'A'的模板参数无效,预期的编译时常量表达式
  1 GT; f:\ documents \ visual studio 2012 \ projects \ test1 \ test1 \ test.cpp(1):见“PTM”声明
  ==========构建:0成功,1个失败,0个最新,0个跳过==========

答案 2 :(得分:0)

使用function_hook代替。基本上这允许你在静态函数的主体中获取成员变量的地址,该函数可以在类Test的主体之外定义。

#include <boost/intrusive/list.hpp>
#include <boost/intrusive/parent_from_member.hpp>

class Test {
protected:
     boost::intrusive::list_member_hook<> order_hook;
private:
     struct hook_access
     {
         typedef boost::intrusive::list_member_hook<> hook_type;
         typedef hook_type* hook_ptr;
         typedef hook_type const* const_hook_ptr;
         typedef Test value_type;
         typedef value_type* pointer;
         typedef value_type const* const_pointer;

         static hook_ptr to_hook_ptr( value_type& i_value )
         { return & i_value.order_hook; }
         static const_hook_ptr to_hook_ptr( value_type const& i_value )
         { return & i_value.order_hook; }
         static pointer to_value_ptr( hook_ptr i_hook );
         static const_pointer to_value_ptr( const_hook_ptr i_hook );
     };
     friend struct hook_access; 
public:
     typedef boost::intrusive::function_hook< Test::hook_access > order_hook_type;
};

Test::hook_access::pointer 
Test::hook_access::to_value_ptr
( Test::hook_access::hook_ptr i_hook )
{ return boost::intrusive::get_parent_from_member< Test >( i_hook, & Test::order_hook ); }

Test::hook_access::const_pointer 
Test::hook_access::to_value_ptr
( Test::hook_access::const_hook_ptr i_hook )
{ return boost::intrusive::get_parent_from_member< Test >( i_hook, & Test::order_hook ); }