【问题标题】:error C2327: not a type name, static, or enumerator错误 C2327:不是类型名称、静态或枚举数
【发布时间】:2013-11-03 01:07:34
【问题描述】:

我在 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

请帮忙。我在 Windows 中缺少什么?

【问题讨论】:

  • 你用的是什么版本的VS?
  • Microsoft Visual Studio 2010 版本 10.0.40219.1 SP1Rel Microsoft .NET Framework 版本 4.0.30319 SP1Rel
  • 嗯,当你把order_hook_type放到课外就可以了……
  • @catscradle 那会是标准方式吗?为此,我必须将 order_hook 设为公开
  • 现在让社区来决定,因为我没有任何线索。 :-)

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


【解决方案1】:

tl;dr:Visual Studio 是对的——你不能把 typedef 放在那里。
Boost 文档gets this right, but doesn't explain why


[C++11: 14.3.2/1]: 非类型、非模板模板参数的模板参数应为以下之一:

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

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

[C++11: 8.3.3/2] 给出了一个不完整类型的指向成员的示例,只要指向成员的指针没有实际初始化,它就有效,尽管没有明确说明,但其含义是实际采取一些C::mC的地址必须是一个完整的类型。事实上,直到C 是一个完整的类型,C::m 才真正存在。

有一些类似的规则更清晰:

[C++11: 9.2/10]:非静态 (9.4) 数据成员不应有不完整的类型。特别是,C 类不应包含C 类的非静态成员,但它可以包含对C 类对象的指针或引用。

就你的typedef而言,Test不是一个完整的类型:

[C++11: 9.2/2]:class-specifier 的结尾} 处,类被视为完全定义的对象类型(3.9)(或完整类型)。在类 member-specification 中,该类在函数体、默认参数、exception-specificationsbrace-or-equal-initializers 用于非静态数据成员(包括嵌套类中的此类内容)。 否则它在自己的类中被认为是不完整的成员规范

因此,您不能在该位置使用指向成员的指针。您必须编写 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>----- 构建开始:项目:test1,配置:调试 Win32 ------
1> 测试.cpp
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8): 错误 C2327: 'B::x' : 不是类型名称、静态或枚举器
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8):错误 C2065:'x':未声明的标识符
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8):错误 C2975:“PTM”:“A”的模板参数无效,预期的编译时常量表达式
1> f:\documents\visual studio 2012\projects\test1\test1\test.cpp(1) :参见“PTM”声明
========== 构建:0 成功,1 失败,0 最新,0 跳过 ==========

【讨论】:

  • 谢谢。这是一个真正的 gr8 信息。我会继续这样做,直到找到新的东西:)
  • 允许typedef decltype(&amp;B::x) a 但不允许typedef A&lt;B, &amp;B::x&gt; a 似乎不一致。 VS2017RC 两者都允许。
  • @Oktalist:C++14 可能放宽了规则。
【解决方案2】:

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


[C++11: 14.3.2/1]: 非类型、非模板模板参数的模板参数应为以下之一:

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

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

[C++11: 3.4.3.1/1]: 如果 qualified-idnested-name-specifier 指定了一个类,则在 nested-name-specifier 之后指定的名称 在类 (10.2) 的范围内查找,但下面列出的情况除外。该名称应代表该类或其基类之一的一个或多个成员(第 10 条)。 [注: 班级成员 可以在其潜在范围 (3.3.7) 的任何位置使用 qualified-id 来引用。 —结束注释] 上述名称查找规则的例外情况如下:

  • 按照 3.4.3 中的规定查找析构函数名称;
  • conversion-function-idconversion-type-idconversion-type-id 的查找方式相同> 在类成员中访问(见 3.4.5);
  • template-idtemplate-argument 中的名称在整个 postfix-expression 出现的上下文中查找.
  • 在 using 声明 (7.3.3) 中指定的名称的查找还可以找到隐藏在同一范围内的类或枚举名称 (3.3.10)。

这里没有任何例外,所以我们看看类成员的“潜在范围”:

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

  1. 在类中声明的名称的潜在范围不仅包括名称声明点之后的声明区域,还包括所有函数体、非静态数据的大括号或等式初始化器该类中的成员和默认参数(包括嵌套类中的此类内容)。
  2. [..]

GCCcorrectly 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>----- 构建开始:项目:test1,配置:调试 Win32 ------
1> 测试.cpp
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8): 错误 C2327: 'B::x' : 不是类型名称、静态或枚举器
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8):错误 C2065:'x':未声明的标识符
1>f:\documents\visual studio 2012\projects\test1\test1\test.cpp(8):错误 C2975:“PTM”:“A”的模板参数无效,预期的编译时常量表达式
1> f:\documents\visual studio 2012\projects\test1\test1\test.cpp(1) :参见“PTM”声明
========== 构建:0 成功,1 失败,0 最新,0 跳过 ==========

【讨论】:

  • 由于一些问题。它在这里是重复的。
  • @kotlomoy:它们是不同的,提出了不同的可能性。社区可以用他们认为正确的投票来决定,因为我不确定。你更喜欢我把 50% 的故事留给自己听?
  • 请注意,我们可以使用此规则在存在重载成员函数的情况下获取一些funky effects
【解决方案3】:

改为使用 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 ); }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-14
    • 2013-11-18
    • 1970-01-01
    相关资源
    最近更新 更多