今天在项目中使用了C++的proper模板类,这个模板类是用来完成其它支持属性的语言关键字“属性”类似作用的。
在我的代码库内收藏了Achilleas Margaritis编写的C++ object properties library。很吸引人而且实用的功能。可惜在我的VS2005中使用时发生了以下两个错误,错误经定位后均出现在property.hpp中:
1、 出错代码:
typedef _property1<C, T>::_property2<A, S> base_class;
错误提示:
warning C4346: “cpp::properties::_property1<C,T>::_property2<A,S>”: 依赖名称不是类型,用“typename”为前缀来表示类型;
2、 出错代码:
class interface {};
错误提示:
error C2332: “class”: 缺少标记名;
*********************************************************
问题1很快查到原因:
*********************************************************
作者:Scott Meyers
译者:fatalerror99 (iTePub's Nirvana)
nested dependent name(嵌套依赖名字)会导致解析困难。例如,假设我们更加愚蠢地
以这种方法开始 print2nd:
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
...
}
这看上去好像是我们将 x 声明为一个指向 C::const_iterator 的 local variable(局
部变量)。但是它看上去如此仅仅是因为我们知道 C::const_iterator 是一个 type(
类型)。但是如果 C::const_iterator 不是一个 type(类型)呢?如果 C 有一个 st
atic data member(静态数据成员)碰巧就叫做 const_iterator 呢?再如果 x 碰巧是
一个 global variable(全局变量)的名字呢?在这种情况下,上面的代码就不是声明
一个 local variable(局部变量),而是成为 C::const_iterator 乘以 x!当然,这
听起来有些愚蠢,但它是可能的,而编写 C++ 解析器的人必须考虑所有可能的输入,甚
至是愚蠢的。
直到 C 成为已知之前,没有任何办法知道 C::const_iterator 到底是不是一个 type(
类型),而当 template(模板)print2nd 被解析的时候,C 还不是已知的。C++ 有一
条规则解决这个歧义:如果解析器在一个 template(模板)中遇到一个 nested depen
dent name(嵌套依赖名字),它假定那个名字不是一个 type(类型),除非你用其它
方式告诉它。缺省情况下,nested dependent name(嵌套依赖名字)不是 types(类型
)。(对于这条规则有一个例外,我待会儿告诉你。)
知道原因就简单了,直接把代码修正为:
typedef typename _property1<C, T>::_property2<A, S> base_class;
问题解决(只能说在Windows平台下VS自带的C++编译器问题解决,其它编译器甚至其它平台上的编译器我可没有去试过)。
*********************************************************
问题2我没查到原因,因为我直接按控制台项目创建示例代码时没出现这样的错误,而在Win32项目创建项目示例代码时就出现这样的报错。因为我大胆猜测,应当VS2005其自带的C++编译器为了支持C++/CLI,将interface列为关键字的缘故。因此编译器认为class interface是两个关键字的罗列,所以才会报“缺少标记名”。所以我的做法如下:
*********************************************************
把property.hpp(就是那个实现property模板类的文件)中所有涉及“interface”的地方完全替换为“_interface”,同时为保持风格统一,将property模板类中所有作用相同的类全修改为下划线开头!(_variable/_read_write/_read_only/_write_only),问题搞定!
不知道Achilleas Margaritis看到了我的解决方案是不是哭笑不得,哈哈~~