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 は、この特定のケースを診断しなくても問題ありません (インスタンス化が発生した場合でも!)。

より具体的には、14.6/7 の (C++03) 標準ルール

非依存の名前で使用される型が、テンプレートが定義された時点では不完全であるが、インスタンス化が行われた時点では完全である場合、およびその型の完全性がプログラムの良し悪しに影響する場合プログラムのセマンティクスが形成されているか影響を与えている場合、プログラムの形式が正しくありません。診断は必要ありません。

したがって、解決策は型を依存させるだけですが、インスタンス化中にその型が指定されるように調整します。たとえば、次のようにテンプレートを書き換えることでそれを行うことができます

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

ただし、それらは非常に密接に結合されているように見えるため、両方のクラスに 1 つのヘッダー ファイルを使用するか、個々のヘッダーを正しい順序で含む 1 つのパブリック ヘッダー ファイルを使用する方がよいでしょう。

于 2010-09-02T22:13:20.347 に答える