2010-09-02 3 views
1

Я работаю над некоторым кодом, который компилирует и связывает (и даже выпускает коммерческие продукты) в Windows с использованием MSVC. Она не компилируется с GCC, хотя, я получаю следующие ошибки:C++ templated function and forward declarations

.../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.

+0

Я подозреваю, что шаблоны - это красная селедка. Можете ли вы снять шаблон и подтвердить, что это все еще проблема? –

+1

Есть ли причина, по которой вы не можете переместить определение 'CBaseValue :: InstanceOf' в' CValueType.h' после определения 'class CValueType'? –

+0

К сожалению, я не могу вытащить шаблоны - это шаблонная функция, на которой основана вся система типов (внутри нашего движка). По этой причине я также не могу (не меняя много кода) переместить функцию из CBaseValue и в CValueType. – user438380

ответ

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>(); 
    // ... 
} 
+0

Хороший улов на зарезервированном идентификаторе '_Type' –

+0

Идентификатор« _Type »никогда не исходил из самого кода, это было просто что-то, что я поставил здесь, чтобы попытаться понять, что это один из наших типов. Я говорю это, потому что я полностью согласен с вами! – user438380

0

Это кажется, что функция CBaseValue::InstanceOf() бесполезно никому не включая CValueType.h.

Так что подождите, чтобы предоставить определение до тех пор, пока не будут доступны все необходимые типы.

CBaseValue.h

class CValueType; 

class CBaseValue { 
public: 

... 

    template <typename _Type> 
    bool InstanceOf(); 

... 

} 

CValueType -: (EDIT Это именно то, что предложенный комментарий Чарльз Бейли, что он писал в то время как я печатал я предполагаю, что мы думаем одинаково.).ч

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

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

+0

Вы абсолютно правы, что эти типы очень тесно связаны - и это была хорошая идея. Спасибо! – user438380

Смежные вопросы