如何为所有 C++ 通用定义插入运算符IOStream 操纵器?
所有,
为什么以下代码无法针对“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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为
endl
是一个函数模板:所以标识符本身不是一个值。它只有在实例化时才变成一个值(函数指针)。但是您的运算符<<本身就是一个模板,编译器没有可用的类型信息来决定使用哪些类型实例化
endl
。相比之下,例如
boolalpha
是:这就是为什么它有效。
endl
适用于basic_ostream
,因为它定义了operator<<
重载作为采用函数指针的成员函数;特别是:所以在像
stream << 这样的调用中endl
,它会从this
的类型(即运算符的左侧)知道charT
和traits
,这会给它右侧期望的函数指针的确切类型 - 然后它将用于实例化endl
的相应版本。您也可以为您的班级做同样的事情。Because
endl
is a function template: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 instantiateendl
with.In contrast, e.g.
boolalpha
is:Hence why it works.
endl
works forbasic_ostream
, because that one definesoperator<<
overloads as member functions taking function pointers; in particular:So in a call like
stream << endl
, it would knowcharT
andtraits
from type ofthis
(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 ofendl
. You can do the same for your class.您需要将流操纵器定义为单独的朋友。
添加这个好友:
然后需要定义函数:
You need to define stream manipulators as a separate friend.
Add this friend:
Then you need to define the function: