首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何泛化定义所有C++ IOStream机械手的插入操作符?

如何泛化定义所有C++ IOStream机械手的插入操作符?
EN

Stack Overflow用户
提问于 2011-05-18 22:44:34
回答 2查看 1.3K关注 0票数 6

全,

为什么下面的代码不能为'std::endl‘编译,但是对于所有其他插入的类型都很好呢?

代码语言:javascript
运行
复制
#include <sstream> // ostringstream

/// @brief A class that does streamed, formatted output via 'operator<<'.
class My_Stream
{
public:
    /// @brief A member method that manipulates the underlying stream.
    void foo()
    {
        m_oss << "foo_was_here; ";
    }

private:
    /// @brief The underlying stream.
    std::ostringstream m_oss;

    /// @brief 'operator<<' is a friend.
    template< typename T >
    friend My_Stream& operator<<( My_Stream& a_r_my_stream,
                                  const T& a_r_value );
};

/// @brief A manipulator that calls a class method.
My_Stream& manipulator_foo( My_Stream& a_r_my_stream )
{
    a_r_my_stream.foo();
    return a_r_my_stream;
}

/// @brief The generic insertion operator.
template< typename T >
My_Stream& operator<<( My_Stream& a_r_my_stream,
                       const T& a_r_value )
{
    a_r_my_stream.m_oss << a_r_value;
    return a_r_my_stream;
}

/// @brief Define an iostream-like manipulator for my-stream.
typedef My_Stream& ( * my_stream_manipulator ) ( My_Stream& );

/// @brief The specialized 'my_stream_manipulator' insertion operator.
template<>
My_Stream& operator<<( My_Stream& a_r_my_stream,
                       const my_stream_manipulator& a_r_manipulator )
{
    return a_r_manipulator( a_r_my_stream );
}

int main( int argc, char* argv[] )
{
    My_Stream my_stream;

    my_stream << 'c'; // char
    my_stream << "string"; // c-string
    my_stream << 1u; // unsigned int
    my_stream << -1; // signed int
    my_stream << 5.3f; // float
    my_stream << -23.345; // double
    my_stream << std::boolalpha; // std::ios_base manipulator
    my_stream << std::endl; // std::ostream manipulator
    my_stream << manipulator_foo; // my_stream manipulator

    return 0;
}

我得到以下G++ 4.5错误:

willo:~/test_cpp$ g++ -Wall test_overloaded_insertion_manipulators.cpp test_overloaded_insertion_manipulators.cpp: In函数‘int(int,char**)’: error: my_stream << std::endl中的operator<<不匹配

我期望代码为std::endl实例化一个'operator<<‘,就像它对原语、std::ios_base和我的自定义操作器所做的那样。

对于上下文,我正在尝试创建一个轻型API类,它可以与当前的IOStream操作程序一起工作,以及另外一个或两个自定义操作程序。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-05-18 23:13:58

因为endl是一个函数模板:

代码语言:javascript
运行
复制
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

因此,标识符本身不是一个值。它只有在实例化时才会变成一个值(函数指针)。但是operator<<本身就是一个模板,编译器没有可用的类型信息来决定使用哪种类型实例化endl

相反,例如boolalpha是:

代码语言:javascript
运行
复制
ios_base& boolalpha(ios_base& str);

所以它才能起作用。

endl适用于basic_ostream,因为它将operator<<重载定义为接受函数指针的成员函数;特别是:

代码语言:javascript
运行
复制
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));

因此,在像stream << endl这样的调用中,它将从this类型(即操作符的左边)了解charTtraits,这将给出在右侧期望的函数指针的确切类型--然后它将用来实例化相应版本的endl。你也可以为你的班级做同样的事情。

票数 8
EN

Stack Overflow用户

发布于 2011-05-18 23:15:27

您需要将流操作器定义为单独的朋友。

加上这个朋友:

代码语言:javascript
运行
复制
// Note: Untested (don't have a compiler here).
template <class charT, class Traits>
friend My_Stream& operator<<( My_Stream&, std::basic_ostream<charT, Traits>& (*)(std::basic_ostream<charT, Traits>&));

然后需要定义函数:

代码语言:javascript
运行
复制
template <class charT, class Traits>
My_Stream& operator<<( My_Stream& stream, std::basic_ostream<charT, Traits>& (*manip)(std::basic_ostream<charT, Traits>&))
{
    (*manip)(stream.m_oss);
    return stream;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6051872

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档