如何为所有 C++ 通用定义插入运算符IOStream 操纵器?

发布于 2024-11-08 10:53:44 字数 2515 浏览 0 评论 0原文

所有,

为什么以下代码无法针对“std::endl”进行编译,但对于所有其他插入类型都可以?

#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:在函数“int main(int, char**)”中: test_overloaded_insertion_manipulators.cpp:60: 错误: 与“operator<<”不匹配在 'my_stream << std::endl'

我希望代码实例化一个 'operator<<'对于 std::endl,就像它对基元、std::ios_base 和我的自定义操纵器所做的那样。

对于上下文,我正在尝试创建一个类似轻 API IOStream 的类,该类可与当前 IOStream 操纵器以及一两个以上自定义操纵器一起使用。

All,

Why does the following code fail to compile for 'std::endl', but it's fine for all of the other inserted types?

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

I get the following G++ 4.5 error:

willo:~/test_cpp$ g++ -Wall test_overloaded_insertion_manipulators.cpp
test_overloaded_insertion_manipulators.cpp: In function ‘int main(int, char**)’:
test_overloaded_insertion_manipulators.cpp:60: error: no match for ‘operator<<’ in ‘my_stream << std::endl’

I expect the code to instantiate a 'operator<<' for std::endl, just like it did for the primitives, std::ios_base and my custom manipulator.

For context, I'm trying to create a light-API IOStream-like class that works with current IOStream manipulators, as well as one or two more custom manipulators.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

墨离汐 2024-11-15 10:53:44

因为 endl 是一个函数模板:

template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

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

相比之下,例如 boolalpha 是:

ios_base& boolalpha(ios_base& str);

这就是为什么它有效。

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

basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));

所以在像 stream << 这样的调用中endl,它会从 this 的类型(即运算符的左侧)知道 charTtraits,这会给它右侧期望的函数指针的确切类型 - 然后它将用于实例化 endl 的相应版本。您也可以为您的班级做同样的事情。

Because endl is a function template:

template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

So the identifier itself is not a value. It only becomes a value (function pointer) when it's instantiated. But your operator<< is itself a template, and there is no type information available to the compiler to decide which types to instantiate endl with.

In contrast, e.g. boolalpha is:

ios_base& boolalpha(ios_base& str);

Hence why it works.

endl works for basic_ostream, because that one defines operator<< overloads as member functions taking function pointers; in particular:

basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));

So in a call like stream << endl, it would know charT and traits from type of this (i.e. left side of operator), and that would give it exact type of function pointer to expect on the right side - which it would then use to instantiate the corresponding version of endl. You can do the same for your class.

鸢与 2024-11-15 10:53:44

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

添加这个好友:

// 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>&));

然后需要定义函数:

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

You need to define stream manipulators as a separate friend.

Add this friend:

// 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>&));

Then you need to define the function:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文