卡住了---用C++创建一个运算符模板
stuck --- Creating an Operator Template in C++
我正在创建一个模仿cout的类SpyOutput,我正在尝试使用一个模板,这样我就不必重载<lt;操作员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;
^
错误消息的关键部分是"模板参数推导/替换失败"。endl
不是一个对象,它甚至不是一个函数。它是一个函数模板,是一个"cookie切割器",用于生成无限数量的cookie函数。当<<
转换为ostream
时,编译器会查看是否有任何潜在的<<
函数可以澄清模板参数应该是什么
ostream& operator<< (ostream& (*pf)(ostream&));
当编译器检查这个重载时,它意识到它可以明确地将endl
专门化为ostream& (*)(ostream&)
,因此选择这个重载并执行与流的类型匹配的隐式专门化。幸运的是,你所要做的就是提供上面的函数重载,希望这个魔术也能为你工作。
需要注意的是,作为成员,ostreams还有另外两个重要的重载:
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));
还值得一提的是,您的函数正试图复制您流式传输的所有对象,这可能会导致它失败或操作不当。一个更明智的想法是使用一个普遍的参考。或者在时至少通过常量引用捕获。
//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;
}
您的代码之所以失败,仅仅是因为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
接口。
相关文章:
- 一个关于在C++中重载布尔运算符的问题
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 为 std::variant 提供一个运算符 ==
- 一元*运算符的操作数是否期望一个 prvalue
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 我在 .h 中有一个枚举类,并且在.cpp错误中有一个运算符重载:与"运算符<<不匹配
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 运算符重载:"operator+"必须采用零个或一个参数
- 重载运算符*以获取对另一个类的实例的引用
- 使用 scope 运算符 (::) 引用另一个文件中的类
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 在一个指令中声明更多指针的运算符优先级
- 为什么有条件编译运算符模板会更改另一个运算符的可用性?
- 我重载了一个运算符*()函数来计算两个矩阵的总和,但编译器提示此错误
- 基于范围的循环使用另一个运算符
- 在C++中,我可以使用箭头运算符访问另一个运算符吗
- 卡住了---用C++创建一个运算符模板
- 为什么一个运算符的操作数需要具有相同的类型
- 是否可以为 C++ 的字符串类创建一个运算符+函数?并连接"literals"?
- 如何为 boost::tuple 编写一个 '<<' 运算符?