模板特化,其中模板化类型也是模板

时间:2009-06-04 00:07:32

标签: c++ templates

我已经为字符串转换创建了一个小实用程序函数,这样我就不必在整个地方创建ostringstream对象

template<typename T>
inline string ToString(const T& x)
{
    std::ostringstream o;
    if (!(o << x))
        throw BadConversion(string("ToString(") + typeid(x).name() + ")");
    return o.str();
}

我想为没有默认重载的实例提供此方法的一些特化&lt;&lt; stringstream的运算符(即std :: pair,std :: set,我自己的类),我遇到了模板的困难。我将用std :: pair示例说明,如果我想能够

string str = ToString(make_pair(3, 4));

我能想到的唯一方法是为int

定义显式特化
template<>
inline string ToString(const pair<int,int>& x)
{
    std::ostringstream o;
    if (!(o << "[" << x.first << "," << x.second << "]"))
        throw BadConversion(string("ToString(pair<int,int>)"));
    return o.str();
}

有没有办法可以为通用案例定义这个?

template<>
inline string ToString(const pair<T1,T2>& x)
{
    std::ostringstream o;
    if (!(o << "[" << x.first << "," << x.second << "]"))
        throw BadConversion(string("ToString(pair<T1,T2>)"));
    return o.str();
}   

2 个答案:

答案 0 :(得分:16)

不要专门化模板,但要超载它。编译器将根据它们对函数参数类型的特殊化来定义要采用的函数模板(这称为部分排序)。

template<typename T1, typename T2>
inline string ToString(const std::pair<T1, T2>& x) {
    std::ostringstream o;
    if (!(o << "[" << x.first << "," << x.second << "]"))
        throw BadConversion(string("ToString(pair<T1,T2>)"));
    return o.str();
}

通常,部分排序会产生您期望的结果。更详细地说,考虑具有这两个功能

template<typename T> void f(T);
template<typename T, typename U> void f(pair<T, U>);

现在,为了看一个是否至少与另一个一样专业,我们测试两个函数模板的以下内容:

  1. 为每个模板参数选择了一些唯一类型,将其替换为函数参数列表。
  2. 使用该参数列表作为参数,在另一个模板上进行参数推导(使用该另一个模板的参数进行虚拟调用)。如果扣除成功并且不需要转换(添加const就是这样)。
  3. 上述示例:

    1. 将某些类型的X1替换为T,为我们提供了一些类型,称之为X1X1pair<T, U>的参数推断不起作用。所以第一个并不像第二个模板那样专业。
    2. 将类型Y1Y2替换为pair<T, U>会产生pair<Y1, Y2>。对第一个模板的T进行参数推断:T将推导为pair<Y1, Y2>。所以第二个至少和第一个一样专业。
    3. 规则是,函数模板A比其他B更专业,如果A至少与B一样专业,但B至少不如A专用。所以,第二个在我们的例子中获胜:它是更专业,如果我们原则上可以调用两个模板函数,它将被选择。

      我担心,这个概述很匆忙,我只是为类型参数做了这个并跳过了一些细节。查看C ++标准规范中的14.5.5.2以查看血腥细节。克

答案 1 :(得分:1)

如何使用类型特征将不同类型的序列化为流,如下所示:

template<typename T>
struct Traits {
  static inline bool ToStream(std::ostringstream& o, const T& x) {
    return o << x;
  }
};

template<typename T1, typename T2>
struct Traits<std::pair<T1, T2> > {
  static inline bool ToStream(std::ostringstream& o, const std::pair<T1, T2>& x) {
    return o << "[" << x.first << "," << x.second << "]";
  }
};

template<typename T>
inline std::string ToString(const T& x)
{
  std::ostringstream o;
  if (!Traits<T>::ToStream(o, x))
    return "Error";
  return o.str();
}

注意:“模板&lt;&gt;”从专业化部分是可选的,代码编译没有它。 您可以在异常消息的特征中进一步添加方法。