1

我正在使用 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'

CBaseValue.h

class CValueType;

class CBaseValue {
public:

...

    template <typename _Type>
    bool InstanceOf() {
        CValueType* pType = GetType();
        if(pType == NULL) {
            return false;
        }
        else {
            return pType->IsDerivedFrom<_Type>();
        }
    }

...

}

CValueType.h

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 的原因。

4

2 回答 2

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>();
    // ...
}
于 2010-09-02T22:05:23.717 回答
0

似乎该CBaseValue::InstanceOf()函数对不包括 CValueType.h 的任何人都没有用。

因此,请等待提供定义,直到所有需要的类型都可用。(编辑:这正是查尔斯·贝利(Charles Bailey)在我打字时发表的评论所暗示的——我想我们的想法是一样的。)

CBaseValue.h

class CValueType;

class CBaseValue {
public:

...

    template <typename _Type>
    bool InstanceOf();

...

}

CValueType.h

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>();
        }
    }

虽然它们看起来非常紧密耦合,所以也许只有一个用于两个类的头文件,或者一个包含正确顺序的各个头文件的公共头文件会更好。

于 2010-09-02T22:13:20.347 回答