Шаблонная функция C++ и прямые объявления

Я работаю над кодом, который компилирует и связывает (и даже выпускает коммерческие продукты) для Windows, используя MSVC. Это не компилируется с 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.

2 ответа

Решение

Стандарт плохо сформулирован, но диагностика не требуется. 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>();
    // ...
}

Кажется, что CBaseValue::InstanceOf() Функция бесполезна для всех, кроме CValueType.h.

Так что ждите, чтобы предоставить определение, пока все необходимые типы не доступны. (РЕДАКТИРОВАТЬ: Это именно то, что предлагается в комментарии Чарльза Бейли, который он разместил, когда я печатал, - я думаю, мы думаем одинаково.)

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

Они кажутся очень тесно связанными, поэтому, возможно, было бы лучше иметь только один заголовочный файл для обоих классов или один общедоступный заголовочный файл, включающий отдельные заголовки в правильном порядке.

Другие вопросы по тегам