Ответ 1
Это запрещено в стандарте С++ 14.7.3/18:
.... декларация не должна явно специализировать член класса шаблон, если его встроенные шаблоны классов не являются явно специализированными также.
У меня есть шаблон класса, вложенный внутри другого шаблона. Частично специализировать это легко: я просто объявляю еще один блок template< … >
внутри своего родителя.
Однако мне нужна другая частичная специализация, которая позволяет указать все его аргументы локального шаблона. Это превращает его в явную специализацию. Явные специализации по любой причине должны быть в области пространства имен. Чтобы объявить его за пределами своего родительского класса, родитель должен быть номинирован, для чего требуется непустой список аргументов шаблона. Это подразумевает частичную специализацию. Частичная специализация - это то, что я делаю, и она должна работать в произвольном внешнем масштабе. Но как GCC, так и Comeau не могут идентифицировать параметр шаблона в родительской номинации с формальными аргументами частичной специализации.
template< class X > struct A {
template< class Y > struct B; // initial declaration OK
template< class Z >
struct B< A< Z > > {}; // partial OK as long as there a local arg
template<> // ERROR: this syntax triggers explicit specialization
struct B< int > {};
};
template<> // ERROR: can't nest template<>s here (why?)
template< class X > // ERROR: can't deduce X from type of A<X>::B<int> (why?)
struct A< X >::B< int > {};
(Я оставил весь свой нерабочий код, прокомментируйте его, чтобы попытаться понять).
Это запрещено в стандарте С++ 14.7.3/18:
.... декларация не должна явно специализировать член класса шаблон, если его встроенные шаблоны классов не являются явно специализированными также.
Я не слишком сильно использую вложенные классы. Моя главная жалоба заключается в том, что они имеют тенденцию раздувать код класса, в который они вложены.
Поэтому я предлагаю другое обходное решение:
namespace detail
{
template <class X, class Z> class BImpl;
template <class X, class Z> class BImpl<X, A<Z> > {};
template <class X> class BImpl<X,int> {};
}
template <class X>
class A
{
template <class Z> struct B: BImpl<X,Z> {};
};
Просто помните, что для передачи X требуется аргумент BImpl
, если вы хотите также специализировать A
. Смешно, что в этом случае я получаю только частичную специализацию!
Сложный материал. Ваш начальный код ICE VC10 Beta2, хорошо.
Во-первых, я думаю, что у вас есть это в обратном направлении:
template<>
template< class X >
struct A< X >::B< int > {};
X является параметром шаблона для структуры A, а B является полностью специализированным, поэтому я думаю, что это должно быть так:
template< class X >
template<>
struct A< X >::B< int > {};
Но даже это не скомпилируется. Текст ошибки действительно полезен, однако:
a.cpp a.cpp(11): ошибка C3212: "A:: B": явный специализация члена шаблона должен быть членом явного специализация a.cpp(8): см. объявление "A:: B"
Похоже, что законно полностью специализировать B, если вы также полностью специализируете A.
Изменить: Хорошо, я слышал от кого-то, кто может говорить на это авторитетно, - перефразировать, это очень мрачная область в стандарте, и это открытая проблема с Комитетом С++ по очистке он ( "он" является явной специализацией членов шаблонов классов). В ближайшей перспективе совет: "Не делай этого".
По крайней мере, это работает в VC 2010. Но я не могу написать def. fun() для "int" вне объявления класса. EDIT: К сожалению, g++ имеет также проблемы с компиляциями. EDIT: приведенный ниже код работал на VC 2010.
template<typename X>
class A
{
public:
A()
{
}
template<typename Y>
struct B
{
void fun();
};
template<>
struct B<int>
{
void fun()
{
cout << "Specialized version called\n";
}
//void fun();
};
public:
B<X> b;
};
template<typename X>
template<typename Y>
void A<X>::B<Y>::fun()
{
cout << "templated version called\n";
}
int main()
{
A<int> a;
a.b.fun();
A<float> a1;
a1.b.fun();
}