运算符的部分专业化()

时间:2010-12-14 14:26:20

标签: c++ templates specialization

我的一个类声明了一个模板化函数:

template<class A, class B>
A do_something(const std::vector<B> &data)

我想部分专注于typename AB是一类实现非常小的接口的类型,我们使用了很多,所以我希望我的专业化在B上是通用的。我怀疑这是双倍的烦恼,因为typename A仅用作返回类型。

从互联网上,我发现我不能部分专门化一个函数,所以我创建了一个类如下:

template<class A, class B> 
class do_something_implementation {
  public:
    do_something_implementation(const std::vector<B> &data_) {
      data = data_;
    }

  int do_something_implementation<int, B>::operator()() {
    /* Complicated algorithm goes here... */
  }

  double do_something_implementation<double, B>::operator()() {
    /* Different complicated algorithm goes here... */
  }

  private:
      std::vector<B> data;
}

当我尝试编译它时(使用Visual Studio 2008),编译器崩溃(!)并且我收到以下错误:

fatal error C1001: An internal error has occurred in the compiler.

我认为这是我的问题而不是编译器。有没有更好的方法来表达我的目标部分专业化?

4 个答案:

答案 0 :(得分:7)

通常,它是这样的:

template <typename A, typename B>
struct DoSomethingHelper
{
    static A doIt(const std::vector<B> &data);
};

template <typename B>
struct DoSomethingHelper<double, B>
{
    static double doIt(const std::vector<B> &data) { ... }
};

template <typename B>
struct DoSomethingHelper<int, B>
{
    static int doIt(const std::vector<B> &data) { ... }
};

template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }

答案 1 :(得分:4)

既然您已经看到了经典的前向静态方法,那么专门化的类型实际上是“完整”的另一种方式。

您可能无法对某个功能进行部分专业化,但您可以完全超载它。

template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }

template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }

template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }

template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }

诀窍是将“未使用”的参数传递给doImpl,其唯一目的是实际选择正确的实现(多亏了重载决策)。

我只是选择传递(A*)0,因为这不涉及A的构造函数(如果它不重要)。

这个调度习惯用法是在STL中用来实现某些迭代器类别效率更高的算法(例如,std::distance对于随机迭代器是O(1)。

我发现使用带有静态方法和部分特化的辅助类更轻量级......但也许只是我:)

答案 2 :(得分:1)

人们通常只是转向静态实现。

template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
    static A do_something(class_type* not_this, const std::vector<B>& data) {
        //...
    }
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
    return X<A, B>::do_something(this, data);
};

答案 3 :(得分:1)

不是问题的解决方案(已经存在一些问题),但代码中存在一些错误:

您在模板类声明中缺少structclass关键字:

template <typename A, typename B> struct do_something_implementation {
//                                ^^^^^^

在类定义中,成员函数不能使用限定名,无论该类是否为模板:

class A {
   void A::foo() {} // Error, should be: void foo() {}
};

成员模板特化不能出现在类定义中,而是出现在命名空间级别:

class B {
   template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}

另外在你的情况下,成员函数不是模板,而是非模板化的成员函数(模板是包含类,而不是函数本身)。你的代码有效地尝试做的是在通用模板中定义其他类的成员函数,尝试这样做。

总的来说,有足够的错误使得解析代码几乎不可能让编译器识别你想要做的事情并提供一个好的错误消息,但是,它应该提供任何错误消息指向你复制的第一行,而不是窒息死亡。