1

我有一个派生的 basic_ostream 类和一个内联修饰符(类似于 setw)。我的流类还应该从其父类继承所有运算符 << 行为。根据我是否使用“using”关键字,我会得到不同的编译器错误:

#include <iostream>

struct modifier { };

template <typename C, typename T=std::char_traits<C> >
struct mystream : public std::basic_ostream<C, T>
{
    // this is where the trouble is
    using std::basic_ostream<C, T>::operator <<;

    inline mystream & operator << (const modifier & mod)
    {
        // ...custom behavior...
        return *this;
    }
};

int main()
{
    mystream<char> foo;
    modifier m;
    foo << "string";  // this fails if the using is present
    foo << 123;       // this fails if the using is absent
    foo << m;
}

当我输入 using 指令时,编译器对“字符串”输出感到困惑,如果我将其注释掉,它会对整数 123 输出感到困惑,在这两种情况下都会给我“错误:'operator<< '”。我对 g++ 4.2.1 和 g++4.8 都有问题。这里的正确前进方向是什么?

4

2 回答 2

3

与其从 std::basic_ostream 继承,不如使用常规流为您的修饰符结构重新实现 << 就足够了:

std::ostream & operator << (std::ostream &stream, const modifier & mod)
{
    // ...custom behavior...
    return stream;
}

您的解决方案似乎过于复杂,但我认为您得到的实际错误来自您的 << 重载 - 它必须接受两个参数(第一个参数是对流本身的引用)。

于 2013-05-03T16:07:35.220 回答
2

没有using,很明显:编译器将找不到 的任何成员重载<<,因为您的函数隐藏了它们。是<<成员,所以没有using,它就会消失。<<不是会员,所以它仍然有效。

当您添加using: 时,所有成员重载都是可见的,就好像它们是您的类的成员一样。并将 "string"转换为char const*. 编译器试图解决的重载是:

operator<<( mystream<char>, char const* ).

现在考虑一些要考虑的重载:

std::ostream& mystream::operator<<( void const* );
std::ostream& mystream::operator<<( bool );
std::ostream& operator<<( std::ostream&, char const* );

对于第一个参数 ( foo, a mystream),前两个函数都比第三个更好(因为它们是完全匹配的);对于第二个参数(字符串文字),第三个函数是更好的匹配。因此:模棱两可。

更一般地说,您的代码存在几个问题。从根本上说,您不会<<通过派生来添加运算符。如您所见,它不起作用。也许更重要的是,例如:

foo << 123 << m;

将不起作用,因为foo << 123返回 a std::ostream&,而不是 a mystream,并且没有 <<哪个可以与 an std::ostream&和 a一起使用modifier<<您可以通过定义新的自由函数来添加运算符:

std::ostream&
operator<<( std::ostream& dest, modifier const& other )
{
    // ...
    return *this;
}

如果您需要额外的数据来格式化,您可以使用xallocand iwordpword来获取它,例如定义一个操纵器:

static int Modifier::modIndex = std::ostream::xalloc();

class mod1
{
    int myModifier;
public: 
    mod1( int m ) : myModifier( m ) {}
    friend std::ostream& operator<<( std::ostream& dest,
                                     mod1 const& mod )
    {
        dest.iword( modIndex ) = myModifier;
        return *this;
    }
};

然后,您可以访问dest.iword( modIndex )以在输出例程中获取此信息。

iword()long&为您的流的每个实例(以及您使用的每个不同的索引)返回一个不同的。

如果您需要更多信息,可以使用pword而不是 iwordpword返回对 a 的引用void*。如果你想用它来指向动态分配的内存,不要忘记注册一个回调来删除它(使用 ios_base::register_callback)。

于 2013-05-03T17:28:20.997 回答