我有一个嵌套在另一个模板中的类模板。部分特殊化很简单:我只在其父级中声明另一个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's 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 > {};
(我把所有非工作代码留下来;适当地评论以试图理解。)
答案 0 :(得分:9)
根据C ++标准14.7.3 / 18:
,这是非法的....声明不应明确专门化一个类成员 模板,如果它的封闭类模板没有明确专门化 同样。
答案 1 :(得分:4)
我倾向于不使用嵌套类太多。我的主要抱怨是他们倾向于膨胀他们嵌套的类的代码。
因此我建议另一种解决方法:
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> {};
};
请注意,如果你想要专门化BImpl
,它需要将X作为参数传递给A
。有趣的是,在这种情况下,我最终只有部分专业化!
答案 2 :(得分:0)
复杂的东西。你的初始代码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”的声明
如果您完全专注于A,那么完全专业化B似乎是合法的。
编辑:好的,我从一位可以权威性地发言的人那里听到了回复 - 这一点在标准中是一个非常模糊的区域,这对于C ++委员会来说是一个公开的问题来清理它(“它”是类模板成员的显式特化)。在短期内,建议是“不要那样做”。
答案 3 :(得分:0)
Atleast这在VC 2010中有效。但是,我无法编写def。类声明之外的“int”的fun()。 编辑:不幸的是,g ++也有编译问题。 编辑:以下代码适用于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();
}