2009-07-15 48 views
48

我重载操作< <的std :: ENDL是未知类型的<<

template <Typename T> 
UIStream& operator<<(const T); 

UIStream my_stream; 
my_stream << 10 << " heads"; 

作品,但:

my_stream << endl; 

给出编译错误:

error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'UIStream' (or there is no acceptable conversion)

什么是为了使my_stream << endl工作的工作?

+0

不知道有关UIStream什么,这是一个有点难以评论。 – 2009-07-15 22:22:39

+10

然而,你找到了一个方法。 :) – notJim 2009-07-15 22:57:09

回答

64

std::endl是一个函数和std::cout通过实施operator<<采取一个函数指针具有相同签名作为std::endl利用它。

在那里,它调用函数,并转发返回值。

这里是一个代码示例:

#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; 
} 

希望这给你的这些东西是如何工作的一个更好的主意。

+3

请在投票时留下评论,以便我可以改进我的答案。 – GManNickG 2009-07-16 05:37:16

+4

我没有downvote,但有一个重要的细节在这里丢失:std :: endl不是一个函数,而是一个模板化函数。这意味着如果你试图定义一个接受operator << overload的泛型操纵符为:`template mystream&operator <<(T&(* fp)(T&))`(这个签名会接受所有的STL`basic_stream <>` ios_base`和`basic_ios <>`操纵符),编译器将无法将std :: endl与模板匹配,因为它本身就是一个模板,并且它不能定义T的含义。 – 2009-07-16 21:46:44

4

有关扩展IOStreams的更好方法,请参见here。 (有点过时了,并且为VC 6量身定制,所以你将不得不采取一粒盐)

关键是要使函子工作(和endl,这两个输出“\ n”和刷新是一个函子)你需要实现完整的ostream接口。

3

由于std流没有虚拟方法,因此不会被设计为子类,所以我认为你不会太过于这样。你可以尝试聚合一个std :: ostream来完成这项工作。

为了使endl工作,你需要实现一个版本的operator<<,需要一个指针到函数,这就是我们的机械手,如endl是即

UStream& operator<<(UStream&, UStream& (*f)(UStream&)); 

UStream& UStream::operator<<(UStream& (*f)(UStream&)); 
处理

现在std::endl是一个函数,它接受并返回对std :: basic_ostream的引用,这样就不会直接与您的流一起工作,因此您需要创建自己的版本, e std::endl版本在您的聚合std::iostream

编辑:看起来很喜欢GMan的回答比较好。他也得到std::endl工作!

31

问题是,std::endl是一个函数模板,因为您的运营商<< 是。所以,当你写:

my_stream << endl; 

你会喜欢的编译器来推断模板参数为操作 以及为endl。这是不可能的。

因此,您必须编写额外的非模板,运算符<<至 与操纵器一起工作。他们的原型看起来像:

UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&)); 

(有两个人,由std::basic_ios<char>std::ios_base,你必须也提供,如果你想允许所有 机械手更换std::ostream),其实施将是非常相似的 您的模板之一。事实上,如此的相似,你可以用你的模板 实现这样的:

typedef std::ostream& (*ostream_manipulator)(std::ostream&); 
UIStream& operator<<(UIStream& os, ostream_manipulator pf) 
{ 
    return operator<< <ostream_manipulator> (os, pf); 
} 

最后一点,经常编写自定义streambuf往往是 一种更好的方式达到什么样的一个努力实现适用于技术,你正在使用。

4

我这样做是为了解决我的问题,这里是我的代码部分:

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/

希望这可以帮助某人。

0

除了公认的答案,用C++ 11有可能超载operator<<的类型:

decltype(std::endl<char, std::char_traits<char>>) 
相关问题