是否可以专门化模板类的特定成员?类似的东西:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
当然,此代码无效。
答案 0 :(得分:27)
您只能通过提供所有模板参数来明确地对其进行专门化。不允许对类模板的成员函数进行部分特化。
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
解决方法是引入重载函数,它们仍然属于同一个类,因此它们对成员变量,函数和东西具有相同的访问权限
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
请注意,通过传递重载函数并将模板参数推送到函数参数,您可以随意“专门化”您的函数,也可以根据需要对它们进行模板化。另一种常见技术是推迟单独定义的类模板
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
我发现通常需要更多的代码,我发现函数重载更容易处理,而其他人更喜欢推迟类模板方式。最后,这是一个品味问题。在这种情况下,您可以将其他模板放在X
内作为嵌套模板 - 在其他情况下,您明确地专门化而不是仅部分专用,那么您不能这样做,因为您可以只放置显式特化在命名空间范围内,而不是在类范围内。
你也可以创建这样一个SpecializedImpl
模板,仅仅是为了函数重载(它的工作方式类似于之前的i2t
),如下面的变量所示,它也留下了第一个参数变量(所以你可以用其他类型调用它 - 而不仅仅是当前实例化的模板参数)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
我认为有时候,推迟到另一个模板会更好(当涉及到数组和指针这样的情况时,重载可能很棘手,只是转发到类模板对我来说更容易),有时只是在模板中重载更好 - 特别是如果你真的转发函数参数,如果你触摸类的成员变量。
答案 1 :(得分:3)
这就是我提出的,并非如此糟糕:)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}