模板化运算符 << 未被识别
Templated operator<< isn't being recognized
我创建了一个名为 SkipToChar 的 class,它应该可以按如下方式使用:
std::ostringstream oss;
oss << "Hello," << SkipToChar(7) << "world!" << std::endl;
这将打印 "Hello, world!"(注意 space。)基本上它应该使用 space 跳到指定索引处的字符。但显然编译器无法识别我为其创建的 operator<<
。有趣的是,显式调用 operator<<
,即使不提供任何模板参数(如 operator<<(oss, SkipToChar(7));
也可以正常工作;如果我实际
则它不起作用
这是我的代码:
#include <iostream>
#include <sstream>
template <typename _Elem>
struct basic_SkipToChar
{
typename std::basic_string<_Elem>::size_type pos;
basic_SkipToChar(typename std::basic_string<_Elem>::size_type position)
{
pos = position;
}
};
template <typename _Elem>
inline std::basic_ostringstream<_Elem> &operator<<(std::basic_ostringstream<_Elem> &oss, const basic_SkipToChar<_Elem> &skip)
{
typename std::basic_string<_Elem>::size_type length = oss.str().length();
for (typename std::basic_string<_Elem>::size_type i = length; i < skip.pos; i++) {
oss << (_Elem)' ';
}
return oss;
}
typedef basic_SkipToChar<char> SkipToChar;
typedef basic_SkipToChar<wchar_t> WSkipToChar;
int main(int argc, char *argv[])
{
std::ostringstream oss;
/*ERROR*/ oss << "Hello," << SkipToChar(8) << "world!" << std::endl;
std::cout << oss.str();
return 0;
}
当我尝试编译它时出现以下错误:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'basic_SkipToChar<char>' (or there is no acceptable conversion)
我用注释标记了错误所在的行。这里出了什么问题?
oss << "Hello,"
returns std::basic_ostream<char>
(丢失字符串部分)。
所以你的方法不匹配(期望 std::basic_ostringstream
但得到 std::basic_ostream<char>
)。
正如 Jarod42 指出的那样,return 类型的 all 的内置
operator<<
是 std::ostream&
。这是一个基本原则
如何流操作员;除了实际的汇或源,
流应该对数据的去向或
来自.
可以提供只为一个工作的操纵器
流的类型,或者对不同类型的流做不同的事情
流,通过在操纵器中使用 dynamic_cast
:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
std::ostringstream* d = dynamic_cast<std::ostringstream*>( &dest );
if ( d != nullptr ) {
// ...
}
return dest;
}
然而,总的来说,这是一个非常糟糕的主意;客户将
非常惊讶输出到一个字符串会导致不同的结果
文本而不是输出到文件。
你似乎试图做的是或多或少地效仿
一种标签形式。最好的方法是使用
过滤输出 streambuf,它跟踪你在哪里
在行中,并且可以插入 std::ostream
和
无论流类型如何,实际接收器:
class TabbingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
int myInLineCount;
public:
TabbingOutputStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myInLineCount( 0 )
{
}
TabbingOutputStreambuf( std::ostream& dest )
: myDest( dest.rdbuf() )
, myOwner( &dest )
, myInLineCount( 0 )
{
myOwner.rdbuf( this );
}
~TabbingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
int overflow( int ch ) override
{
if ( ch == '\n' ) {
myInLineCount = 0;
} else {
++ myInLineCount;
}
return myDest->sputc( ch );
}
// Special function...
int tabTo( int n )
{
int retval = 0;
while ( retval == 0 && myInLineCount < n ) {
if ( overflow( ' ' ) == EOF ) {
retval = EOF;
}
}
return retval;
}
};
你的操纵器将是:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
TabbingOutputStreambuf* sb = dynamic_cast<TabbingOutputStreambuf*>( dest.rdbuf() );
assert( sb != nullptr );
try {
if ( sb->tabTo( manip.pos ) == EOF ) {
dest.setstate( std::badbit );
}
} catch ( ... ) {
dest.setstate( std::badbit );
}
return dest;
}
这仍然不理想,因为它会因不受保护而失败
缓冲区,但您只能在如下上下文中使用操纵器:
void
generateOutput( std::ostream& dest )
{
TabbingOutputStreambuf tabber( dest );
dest << "Hello, " << SkipToChar( 7 ) << "world!";
// ...
}
无论传递给的流类型如何,这都将起作用
功能(包括您不使用的自定义 ostream 类
甚至知道)。
编辑:
最后一点:在基本版本可用之前,不要费心制作模板。 (就其价值而言,您的代码无论如何都无法在 wchar_t 流中正常工作。要在其中输出 space,您需要获取嵌入式语言环境,从 ctype
方面获取它,并使用它的 widen
成员函数。)
我创建了一个名为 SkipToChar 的 class,它应该可以按如下方式使用:
std::ostringstream oss;
oss << "Hello," << SkipToChar(7) << "world!" << std::endl;
这将打印 "Hello, world!"(注意 space。)基本上它应该使用 space 跳到指定索引处的字符。但显然编译器无法识别我为其创建的 operator<<
。有趣的是,显式调用 operator<<
,即使不提供任何模板参数(如 operator<<(oss, SkipToChar(7));
也可以正常工作;如果我实际
这是我的代码:
#include <iostream>
#include <sstream>
template <typename _Elem>
struct basic_SkipToChar
{
typename std::basic_string<_Elem>::size_type pos;
basic_SkipToChar(typename std::basic_string<_Elem>::size_type position)
{
pos = position;
}
};
template <typename _Elem>
inline std::basic_ostringstream<_Elem> &operator<<(std::basic_ostringstream<_Elem> &oss, const basic_SkipToChar<_Elem> &skip)
{
typename std::basic_string<_Elem>::size_type length = oss.str().length();
for (typename std::basic_string<_Elem>::size_type i = length; i < skip.pos; i++) {
oss << (_Elem)' ';
}
return oss;
}
typedef basic_SkipToChar<char> SkipToChar;
typedef basic_SkipToChar<wchar_t> WSkipToChar;
int main(int argc, char *argv[])
{
std::ostringstream oss;
/*ERROR*/ oss << "Hello," << SkipToChar(8) << "world!" << std::endl;
std::cout << oss.str();
return 0;
}
当我尝试编译它时出现以下错误:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'basic_SkipToChar<char>' (or there is no acceptable conversion)
我用注释标记了错误所在的行。这里出了什么问题?
oss << "Hello,"
returns std::basic_ostream<char>
(丢失字符串部分)。
所以你的方法不匹配(期望 std::basic_ostringstream
但得到 std::basic_ostream<char>
)。
正如 Jarod42 指出的那样,return 类型的 all 的内置
operator<<
是 std::ostream&
。这是一个基本原则
如何流操作员;除了实际的汇或源,
流应该对数据的去向或
来自.
可以提供只为一个工作的操纵器
流的类型,或者对不同类型的流做不同的事情
流,通过在操纵器中使用 dynamic_cast
:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
std::ostringstream* d = dynamic_cast<std::ostringstream*>( &dest );
if ( d != nullptr ) {
// ...
}
return dest;
}
然而,总的来说,这是一个非常糟糕的主意;客户将 非常惊讶输出到一个字符串会导致不同的结果 文本而不是输出到文件。
你似乎试图做的是或多或少地效仿
一种标签形式。最好的方法是使用
过滤输出 streambuf,它跟踪你在哪里
在行中,并且可以插入 std::ostream
和
无论流类型如何,实际接收器:
class TabbingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
int myInLineCount;
public:
TabbingOutputStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myInLineCount( 0 )
{
}
TabbingOutputStreambuf( std::ostream& dest )
: myDest( dest.rdbuf() )
, myOwner( &dest )
, myInLineCount( 0 )
{
myOwner.rdbuf( this );
}
~TabbingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
int overflow( int ch ) override
{
if ( ch == '\n' ) {
myInLineCount = 0;
} else {
++ myInLineCount;
}
return myDest->sputc( ch );
}
// Special function...
int tabTo( int n )
{
int retval = 0;
while ( retval == 0 && myInLineCount < n ) {
if ( overflow( ' ' ) == EOF ) {
retval = EOF;
}
}
return retval;
}
};
你的操纵器将是:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
TabbingOutputStreambuf* sb = dynamic_cast<TabbingOutputStreambuf*>( dest.rdbuf() );
assert( sb != nullptr );
try {
if ( sb->tabTo( manip.pos ) == EOF ) {
dest.setstate( std::badbit );
}
} catch ( ... ) {
dest.setstate( std::badbit );
}
return dest;
}
这仍然不理想,因为它会因不受保护而失败 缓冲区,但您只能在如下上下文中使用操纵器:
void
generateOutput( std::ostream& dest )
{
TabbingOutputStreambuf tabber( dest );
dest << "Hello, " << SkipToChar( 7 ) << "world!";
// ...
}
无论传递给的流类型如何,这都将起作用 功能(包括您不使用的自定义 ostream 类 甚至知道)。
编辑:
最后一点:在基本版本可用之前,不要费心制作模板。 (就其价值而言,您的代码无论如何都无法在 wchar_t 流中正常工作。要在其中输出 space,您需要获取嵌入式语言环境,从 ctype
方面获取它,并使用它的 widen
成员函数。)