【发布时间】:2011-12-06 04:36:56
【问题描述】:
这是了解转换运算符、模板和模板专业化的主要学术练习。以下代码中的转换运算符模板适用于 int、float 和 double,但与 std::string... 一起使用时会失败。我创建了转换为std::string 的特化,它在与初始化std::string s = a; 一起使用时有效,但在与演员static_cast<std::string>(a) 一起使用时失败。
#include <iostream>
#include <string>
#include <sstream>
class MyClass {
int y;
public:
MyClass(int v) : y(v) {}
template <typename T>
operator T() { return y; };
};
template<>
MyClass::operator std::string() {
std::stringstream ss;
ss << y << " bottles of beer.";
return ss.str();
}
int main () {
MyClass a(99);
int i = a;
float f = a;
double d = a;
std::string s = a;
std::cerr << static_cast<int>(a) << std::endl;
std::cerr << static_cast<float>(a) << std::endl;
std::cerr << static_cast<double>(a) << std::endl;
std::cerr << static_cast<std::string>(a) << std::endl; // Compiler error
}
上面的代码在 g++ 和 icc 中生成编译器错误,两者都抱怨没有用户定义的转换适合将 MyClass 实例转换为 std::string 上的 static_cast (C 样式转换行为相同)。
如果我用转换运算符的显式、非模板版本替换上面的代码,一切都会好起来的:
class MyClass {
int y;
public:
MyClass(int v) : y(v) {}
operator double() {return y;}
operator float() {return y;}
operator int() {return y;}
operator std::string() {
std::stringstream ss;
ss << y << " bottles of beer.";
return ss.str();
}
};
std::string 的模板特化有什么问题?为什么它可以用于初始化而不是强制转换?
更新:
经过@luc-danton 的一些模板魔法(我以前从未见过的元编程技巧),在启用实验性 C++0x 扩展后,我有以下代码在 g++ 4.4.5 中工作。除了对这里所做的事情的恐惧之外,仅需要实验性编译器选项就足以不这样做。无论如何,希望这对其他人和我一样具有教育意义:
class MyClass {
int y;
public:
MyClass(int v) : y(v) {}
operator std::string() { return "nobody"; }
template <
typename T
, typename Decayed = typename std::decay<T>::type
, typename NotUsed = typename std::enable_if<
!std::is_same<const char*, Decayed>::value &&
!std::is_same<std::allocator<char>, Decayed>::value &&
!std::is_same<std::initializer_list<char>, Decayed>::value
>::type
>
operator T() { return y; }
};
这显然会强制编译器为std::string 选择转换operator std::string(),从而克服编译器遇到的任何歧义。
【问题讨论】:
-
可能相关,但我不确定具体如何:gotw.ca/publications/mill17.htm
-
@sth:链接的文章讨论了模板专业化和解析顺序。为了查看这是否是我遇到的问题(似乎合理),我删除了我对 std::string 的专业化。不幸的是,转换导致 same 编译器错误。如果这是一个不同的错误,我会说它可能是相关的。唉,看来不是这样。
-
这就是文章的重点:特化不有助于解决重载问题。
标签: c++ templates metaprogramming template-specialization