特定成员的模板专业化?

Template specialization of particular members?

提问人:sold 提问时间:10/1/2009 最后编辑:Johannes Schaub - litbsold 更新时间:10/5/2011 访问量:7887

问:

是否可以对模板类的特定成员进行专用化?像这样:

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()
{
    ...
}

当然,这段代码是无效的。

C 模板 专项课程 C++-FAQ

评论

0赞 Daniel Bingham 10/1/2009
目前还不完全清楚你在这里的意思。您的意思是强制模板参数成为某种类型的后代吗?就像在 Java 中使用 <T extends O>?
2赞 Khaled Alshaya 10/1/2009
@Alcon 在专门化一个模板类时,他必须为整个类提供不同的实现。在我看来,除了少数函数之外,他希望在专业化之间共享通用代码。
0赞 Aaron McDaid 8/19/2015
这个问题应该说“成员功能”而不是“成员”吗?为了让没有人认为这是关于数据成员的。

答:

3赞 Khaled Alshaya 10/1/2009 #1

这就是我想出的,还不错:)

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

评论

6赞 curiousguy 10/27/2011
你不是在压倒一切,你只是在躲藏。
30赞 Johannes Schaub - litb 10/1/2009 #2

您只能通过提供所有模板参数来显式地使其专用化。不允许对类模板的成员函数进行部分专用化。

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

我发现这通常需要更多的代码,我发现函数重载更容易处理,而其他人则更喜欢 defer to class template 方式。归根结底,这是一个品味问题。在这种情况下,您也可以将其他模板作为嵌套模板放入其中 - 在其他情况下,您显式专用化而不是仅部分专用化,则无法这样做,因为您只能将显式专用化放置在命名空间范围内,而不能放在类范围内。X

您也可以创建这样的模板,只是为了函数重载(它的工作方式类似于我们之前的),因为以下变体演示了它也留下了第一个参数变量(因此您可以使用其他类型调用它 - 而不仅仅是使用当前实例化的模板参数)SpecializedImpli2t

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>) {
      // ...
    }
};

我认为有时,推迟到另一个模板会更好(当涉及到数组和指针等情况时,重载可能会很棘手,然后转发到类模板对我来说更容易),有时只是在模板内重载会更好 - 特别是如果你真的转发函数参数并且你触摸类的成员变量。

评论

0赞 Xeo 10/26/2011
现在 C++ 已经出来了,这应该使用我认为。会自己编辑,但在 iPod Touch 上的移动视图中真的很麻烦......std::integral_constant
0赞 WhozCraig 12/14/2012
+1 有很多可能性,其中任何一种都可能比另一种更适合 OP。