我已经为字符串转换创建了一个小的实用函数,这样我就不必到处创建 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();
}
我想为字符串流没有默认重载 << 运算符(即 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();
}
最佳答案
不要专门化模板,而是重载它。编译器将根据函数参数类型的特化(这称为部分排序)对它们进行排序,从而找出要采用的函数模板。
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>);
现在,为了查看一个是否至少与另一个一样专业,我们对两个函数模板进行了以下测试:
- 为每个模板参数选择一些独特的类型,将其替换到函数参数列表中。
- 将该参数列表作为参数,对另一个模板进行参数推导(使用这些参数对另一个模板进行虚拟调用)。如果推演成功,不需要转换(加const就是这样)。
上面的例子:
- 替换某种类型
X1
进入T
给我们一些类型,称之为X1
.X1
的论证推导反对pair<T, U>
不会工作。所以第一个至少不像第二个模板那样专业。 - 替换类型
Y1
和Y2
进入pair<T, U>
产量pair<Y1, Y2>
.对T
进行论证推导第一个模板的作品:T
将被推断为pair<Y1, Y2>
.所以第二个至少和第一个一样专业。
规则是,函数模板 A 比另一个 B 更专业,如果 A 至少与 B 一样专业,但 B 至少不与 A 一样专业。因此,在我们的示例中,第二个获胜:它是更专业,如果我们原则上可以调用两个模板函数,就会选择它。
恐怕,那个概述很匆忙,我只是针对类型参数做了它并跳过了一些细节。查看14.5.5.2
在 C++ 标准规范中查看详细信息。克
关于c++ - 模板特化,其中模板化类型也是模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/947943/