我重载了运算符<<
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
可以使用,但是:
my_stream << endl;
编译错误:
错误 C2678: 二进制“<<”:找不到接受左操作数类型为“UIStream”的运算符(或者没有可接受的转换)
如何解决 my_stream << endl
的问题?
我重载了运算符<<
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
可以使用,但是:
my_stream << endl;
编译错误:
错误 C2678: 二进制“<<”:找不到接受左操作数类型为“UIStream”的运算符(或者没有可接受的转换)
如何解决 my_stream << endl
的问题?
std::endl
是一个函数,std::cout
通过实现与std::endl
具有相同函数签名的函数指针的operator<<
来使用它。
在这里,它调用该函数,并向前传递返回值。
这里是一个代码示例:
#include <iostream>
struct MyStream
{
template <typename T>
MyStream& operator<<(const T& x)
{
std::cout << x;
return *this;
}
// function that takes a custom stream, and returns it
typedef MyStream& (*MyStreamManipulator)(MyStream&);
// take in a function with the custom signature
MyStream& operator<<(MyStreamManipulator manip)
{
// call the function, and return it's value
return manip(*this);
}
// define the custom endl for this stream.
// note how it matches the `MyStreamManipulator`
// function signature
static MyStream& endl(MyStream& stream)
{
// print a new line
std::cout << std::endl;
// do other stuff with the stream
// std::cout, for example, will flush the stream
stream << "Called MyStream::endl!" << std::endl;
return stream;
}
// this is the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// this is the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
MyStream& operator<<(StandardEndLine manip)
{
// call the function, but we cannot return it's value
manip(std::cout);
return *this;
}
};
int main(void)
{
MyStream stream;
stream << 10 << " faces.";
stream << MyStream::endl;
stream << std::endl;
return 0;
}
this gives you a better idea of how these things work.template <typename T> mystream& operator<<( T& (*fp)(T&) )
(此签名将接受所有STL basic_stream<>
,ios_base
和basic_ios<>
操纵器),编译器将无法将std::endl与模板匹配,因为它本身也是一个模板,并且无法定义T的含义。 - David Rodríguez - dribeastypedef CoutType
而不是直接使用 ostream
? - cp.engr问题在于std::endl
是一个函数模板,就像你的<<
操作符一样。因此,当你写:
my_stream << endl;
您希望编译器推断运算符的模板参数,以及与endl
相关的模板参数。这是不可能的。
因此,您必须编写额外的非模板重载函数来处理操纵符。它们的原型将如下:
UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));
(还有两个替换std::ostream
为std::basic_ios<char>
和
std::ios_base
的,如果想允许所有操作符,则必须提供它们)它们的实现与您的模板非常相似。 实际上,非常相似,以至于您可以使用您的模板进行如下实现:
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
return operator<< <ostream_manipulator> (os, pf);
}
最后提醒一点,通常编写自定义的streambuf
往往是实现您正在使用的技术所希望实现的更好方法。
pf(*this); return *this;
,但是我将 op<<
添加为我的派生 ostreamer 类的成员。 - TrueY template<typename T>
CFileLogger &operator <<(const T value)
{
(*this).logFile << value;
return *this;
}
CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
{
(*this).logFile << os;
return *this;
}
Main.cpp
int main(){
CFileLogger log();
log << "[WARNINGS] " << 10 << std::endl;
log << "[ERRORS] " << 2 << std::endl;
...
}
我在这里找到了参考资料:http://www.cplusplus.com/forum/general/49590/
希望这能帮助到某些人。
std
流不是为了子类化而设计的,因为它们没有虚方法,所以我认为你在这方面不会有太大的进展。但你可以尝试聚合一个std::ostream来完成工作。
为了让endl
正常工作,你需要实现一个版本的operator<<
,该版本接受指向函数的指针,因为操作符例如endl
都是通过这种方式处理的。
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
或者
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
std::endl
是一个函数,它接受并返回对std::basic_ostream的引用,因此不能直接与您的流一起使用,所以您需要创建自己的版本,调用聚合的std::iostream
中的std::endl
版本。std::endl
正常工作了!除了已经被接受的答案之外,在C++11中还可以重载 operator<<
来处理该类型:
decltype(std::endl<char, std::char_traits<char>>)