2014-09-25 3 views
2

У меня проблема с вложенными шаблонами классов в MSVC 12 и GCC 4.8. Я уменьшил его до следующего фрагмента кода:MSVC: «использование шаблона класса требует списка аргументов шаблона» внутри контейнеров STL

#include <vector> 
#include <list> 

template <typename A, typename B> 
struct Base 
{ 
    template <typename A2, typename B2> struct InBase { }; 
}; 

template <typename A, typename B> 
struct Derived : public Base<A, B> 
{ 
    typedef Base<A, B> MyBase; 

    // this works on GCC 4.8 
    typedef typename MyBase::template InBase<A, B> MyInBase; 
    // this works on MSVC 12 
    typedef MyBase::InBase<A, B> MyInBase; 

    typedef std::vector<MyInBase*> MyInBaseVector; 
    typedef std::list<MyInBase*> MyInBaseList; 

    MyInBaseList list; 
}; 

Когда я использую вариант MSVC из MyInBase на GCC, он просто говорит мне, чтобы добавить typename и template, которые я нахожу понятно. Когда я использую вариант GCC на MSVC (который я считаю это правильным), он сообщает об этом:

deptypes.cpp(20) : error C2955: 'Base<A,B>::InBase' : use of class template requires template argument list 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 
    deptypes.cpp(24) : see reference to class template instantiation 'Derived<A,B>' being compiled 
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\vector(648) : error C2955: 'Base<A,B>::InBase' : use of class template requires template argument list 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 
deptypes.cpp(21) : error C2955: 'Base<A,B>::InBase' : use of class template requires template argument list 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\list(859) : error C2955: 'Base<A,B>::InBase' : use of class template requires template argument list 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 
    deptypes.cpp(7) : see declaration of 'Base<A,B>::InBase' 

ли ошибка MSVC правильно? Если да, как я могу это исправить?

+1

Я бы подумал 'typedef typename MyBase :: InBase MyInBase' –

+0

@NeilKirk: попробовал, работает для MSVC, но GCC по-прежнему запрашивает ключевое слово' 'template''. Так что это более или менее то же самое, что и раньше. – mooware

+2

Вам нужны как 'typename', так и' template'. MSVC просто несоответствует там. –

ответ

3

MSVC отвергает действительный код здесь, как N3337 14.2 (temp.names) p4 состояний:

Когда на экране отображается название шаблона члена специализации после . или -> в постфикса экспрессии или после вложенного-имени-спецификатора в квалифицированного идентификатора, и выражение объекта в постфиксе экспрессии является типом-зависимым или вложенное-имя-спецификатор в квалифицированного идентификатора относится к типу зависимому, но имя не является член текущего экземпляра (14.6.2.1), имя шаблона члена должны быть приставки по ключевому слову template. В противном случае предполагается, что имя имеет имя без шаблона.

Учитывая это, я проверил ваш образец против МУСА 13 и Clang 3.3 на Godbolt: ICC правильно отвергает этот MSVC-изм с nontype "Base<A, B>::InBase [with A=A, B=B]" is not a template при приеме совместимых (typename/template квалифицированные) версии, в то время как Clang, что интересно, принимает как сопутствующие , так и несоответствующие typedefs! Моя локальная копия MSVC 11 (VS2012) также отклоняет версию с template и typename в ней, а также передает список аргументов шаблона, как показывает ошибка (которая в любом случае плохо сформирована).

Оказывается, что template ключевого слова является то, что отключение MSVC, тоже, что предотвращает GCC 4.9 по предложению использования в противном случае резервирования Derived::MyBase::template InBase<A, B> заставить выражение в зависимое контексте без использования typename от работы.

Разработчики Visual Studio уже aware of a very similar issue to this. Что же касается его работы? Вам просто нужно использовать блок #ifdef _MSC_VER для размещения специфической для MSVC версии typedef.

Для педантов: ICC, для всех, что он разорван в некоторых уголках мира, делает в соответствии со стандартами C++ на практике, так как использует тот же EDG-интерфейс, что и Comeau C++.

+1

Спасибо за подробный анализ.Мое текущее обходное решение, которое работает без ifdefs, заключается в использовании структуры для обертывания указателя, а затем поместить эту структуру в вектор. – mooware

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