我正在使用MSVC在Windows上编写一些编译和链接(甚至已发布商业产品)的代码。它不能用GCC编译,但我得到以下错误:
.../CBaseValue.h: In member function 'bool CBaseValue::InstanceOf()':
.../CBaseValue.h:90:18: error: invalid use of incomplete type 'struct CValueType'
.../CBaseValue.h:11:7: error: forward declaration of 'struct CValueType'
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<_Type>();
}
}
...
}
class CValueType : public CBaseValue {
public:
...
template <typename _Type>
bool IsDerivedFrom() {
return IsDerivedFrom(_Type::TYPEDATA);
}
...
}
我理解为什么这是一个问题。基类(CBaseValue)有一个模板化函数,它使用派生类(在本例中为CValueType)。
看起来MSVC在这里并没有完全遵守C ++规范,我只是被它咬了。但是,直到代码调用模板化函数实际编译时使用前向声明的MSVC行为现在也更加可取。有没有人知道我可以在没有重写大量基本代码的情况下使用GCC来处理这些代码?
从我自己的研究看起来将'-fno-implicit-templates'传递给g ++会有所帮助,但是我需要明确定义被调用的模板类型。如果我可以避免它,我会更喜欢它。如果普遍的共识是这是我最好的选择......那就这样吧!
如果有人想知道,我正在将代码移植到Mac上,这就是为什么我们现在正在使用GCC。
答案 0 :(得分:4)
标准不正确,但不需要诊断。 MSVC很好不诊断这个特定情况(即使实例化发生!)。
更具体地说,(C ++ 03)标准规则为14.6 / 7
如果非依赖名称中使用的类型在定义模板但在完成实例化时完成,并且该类型的完整性影响程序是否完整如果程序结构良好或影响程序的语义,程序就是格式错误;无需诊断。
因此,解决方案是仅使类型依赖,但安排它在实例化期间指定该类型。例如,你可以通过像这样重写你的模板来做到这一点
template<typename T, typename> // just ignore second param!
struct make_dependent { typedef T type; };
template <typename Type> // eww, don't use "_Type" in user code
bool InstanceOf() {
typename make_dependent<CValueType, Type>::type* pType = GetType();
// ...
return pType->template IsDerivedFrom<Type>();
// ...
}
答案 1 :(得分:0)
似乎CBaseValue::InstanceOf()
函数对不包括CValueType.h的任何人都没用。
等待提供定义,直到所有需要的类型都可用。 (编辑:这正是Charles Bailey在我打字时发表的评论所暗示的 - 我想我们的想法相似。)
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf();
...
}
class CValueType : public CBaseValue {
public:
...
template <typename T>
bool IsDerivedFrom() {
return IsDerivedFrom(T::TYPEDATA);
}
...
}
template <typename T>
inline bool CBaseValue::InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<T>();
}
}
它们看起来非常紧密耦合,所以可能只有一个头文件用于这两个类,或者一个公共头文件包含正确顺序的各个头文件,会更好。