我正在创建一个模仿cout的类SpyOutput,我正在尝试使用模板,所以我不必重载<<运算符4次(每种数据类型一个):
#include <iostream>
#include <sstream>
using namespace std;
class SpyOutput
{
ostream *os;
stringstream ss;
int sum, temp;
public:
SpyOutput(ostream *s):os(s), sum(0){}
template <class T>
SpyOutput& operator<<(T x)
{
ss << x;
*os << x;
return *this;
}
};
int main(void)
{
SpyOutput spy(&cout);
spy << "Hello" << endl;
spy << "1235" << endl;
spy << 'z' << endl;
spy << 4.56 << endl;
return 0;
}
我无法编译,它似乎无法识别我的模板。有任何想法吗? G ++错误消息是
main.cpp: In function 'int main()':
main.cpp:24:20: error: no match for 'operator<<' (operand types are 'SpyOutput' and '<unresolved overloaded function type>')
spy << "Hello" << endl;
^
main.cpp:24:20: note: candidates are:
main.cpp:13:16: note: template<class T> SpyOutput& SpyOutput::operator<<(T)
SpyOutput& operator<<(T x)
^
main.cpp:13:16: note: template argument deduction/substitution failed:
main.cpp:24:23: note: couldn't deduce template parameter 'T'
spy << "Hello" << endl;
^
答案 0 :(得分:0)
错误消息的关键部分是&#34;模板参数扣除/替换失败&#34;。 endl
不是一个对象,它甚至不是一个函数。它是一个函数 template ,它是一个&#34; cookie cutter&#34;用于生成无限数量的cookie函数。当<<
到ostream
时,编译器会查看是否有任何潜在的<<
函数可以阐明模板参数应该是什么。存在这种过载:
ostream& operator<< (ostream& (*pf)(ostream&));
当编译器检查此重载时,它意识到它可以明确地将endl
专门化为ostream& (*)(ostream&)
,因此选择此重载并执行与流类型匹配的隐式特化。幸运的是,你所要做的就是提供上面的函数重载,希望这个魔法对你也有用。
作为一个注释,ostreams还有两个重要的重载作为你必须添加的成员:
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));
还值得一提的是,您的函数正在尝试复制您流式传输的所有对象,这可能导致其失败或行为不正常。更明智的想法是使用通用引用。或者通过const引用至少捕获。
//if T is a template, then T&& is a universal reference. A perfect match for everything
//if T were not a template, it would be an rvalue reference. Totally unrelated.
template <class T> SpyOutput& operator<<(T&& x) {
ss << x;
*os << x;
return *this;
}
答案 1 :(得分:0)
您的代码失败只是因为std::endl
是函数模板,因此编译器需要知道您要使用的模板的实例化。标准IOStream类对操纵器具有单独的重载,并且它们显式指定模板实例化。你也可以这样做:
SpyOutput& operator<<(std::ostream& (*manip)(std::ostream&))
{
if (os) manip(*os);
return *this;
}
现在当你执行spy << std::endl
时,这将实例化有效的std::endl<char, std::char_traits<char>>
,代码将起作用。虽然通常我不会重新创建整个流类,而是使用std::streambuf
接口。