1

在尝试开发一个从两者继承的类std::stringbufstd::ostream为其提供自定义operator<<()重载(这应该适用于此类,但std::ostream通常不适用于)时,我遇到了一些我不明白的歧义错误。

问题在以下代码的下半部分。如果我删除operator<<()重载,我不会收到任何错误(g++ --std=c++17 -o foo.exe foo.cpp使用 g++ 9.2.0,MSYS2 在 Windows 上构建)。

#include <iostream>
#include <ostream>
#include <sstream>

class MyStream:
    private std::stringbuf,
    public std::ostream
{
public:
    MyStream() noexcept:
        std::stringbuf(),
        std::ostream(this)
    {}

    ~MyStream()
    {
        if (pptr() - pbase() < 2)
        { sync(); }
    }

protected:
    virtual int sync() override
    {
        // make sure there actually is something to sync
        if (pptr() - pbase() < 2)
        { return 0; }

        const std::string message{str()};
        const std::size_t length{message.length()};

        // update the pointers for the next sync
        setp(pbase() + length, epptr());

        std::cout << message;

        return std::stringbuf::sync();
    }
};

MyStream& operator<<(MyStream& out, bool boolean) noexcept
{ return out << (boolean ? "yes" : "no"); }
/*           ↑
    more than one operator "<<" matches these operands:
        -- function template "std::basic_ostream<_Elem, _Traits>
            &std::operator<<(std::basic_ostream<_Elem, _Traits> &_Ostr, const char *_Val)"
        -- function template "std::basic_ostream<char, _Traits>
            &std::operator<<(std::basic_ostream<char, _Traits> &_Ostr, const char *_Val)"
        -- function template "std::basic_ostream<_Elem, _Traits>
            &std::operator<<(std::basic_ostream<_Elem, _Traits> &_Ostr, const _Elem *_Val)"
        -- function "operator<<(MyStream &out, bool boolean) noexcept"
        -- operand types are: MyStream << const char *
*/

int main()
{
    MyStream stream;

    stream << "Hello World" << std::endl;
    /*     ↑
        more than one operator "<<" matches these operands:
            -- function template "std::basic_ostream<_Elem, _Traits>
                &std::operator<<(std::basic_ostream<_Elem, _Traits> &_Ostr, const char *_Val)"
            -- function template "std::basic_ostream<char, _Traits>
                &std::operator<<(std::basic_ostream<char, _Traits> &_Ostr, const char *_Val)"
            -- function template "std::basic_ostream<_Elem, _Traits>
                &std::operator<<(std::basic_ostream<_Elem, _Traits> &_Ostr, const _Elem *_Val)"
            -- function "operator<<(MyStream &out, bool boolean) noexcept"
            -- operand types are: MyStream << const char [12]
    */
}

为什么我对于bool一个有效的char*论证候选人来说是超载的?我怎样才能正确地做到这一点?

4

1 回答 1

1

似乎在linux (g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0) 下对我有用:

MyStream& operator<<(MyStream& out, bool boolean)
{
    out << (boolean ? "yes" : "no");
    return out;
}

我只更改了回拨电话。那是因为out << (boolean ? "yes" : "no")将使用类型的基数ostream operator<<char*因此返回std::basic_ostream<char>类型而不是MyStream返回值类型。

然后在main()使用bool带有MyStream operator<< 作品的类型时:

int main()
{
    MyStream stream;
    bool b=true;

    stream << b << "Hello World" << b << std::endl;  

    //by contrast, this should output "yesHello Worldyes"
    //stream << b << "Hello World";
    //stream << b << std::endl;

    //and so would this kind of ugliness! lol
    //static_cast<MyStream&>(stream << b << "Hello World") << b << std::endl;
}

..但是一旦为语句的一部分ostream operator<<调用基类,它当然会返回一个类型:)"Hello World"std::basic_ostream<char>

..然后在那之后,因为类型不存在ostream operator<< ,类型将被隐式提升为 a ,因此输出为: ! boolbool bint

yesHello World1


Windows 版本

但是您似乎遇到了其他错误。因此,虽然我手头没有 MSYS2,但我确实尝试使用 Visual Studio 在 WinOS 上编译代码。就我而言,至少,main()由于 VS STL 实现引起的歧义,您会立即失败:

int main()
{
    MyStream stream;
    stream << "Hello World" << std::endl;
}

无需对您当前的方法产生怀疑,因为评论中已经发生了这种情况。但只是为了回答您的问题;那么一种方法是operator<<MyStream处理char*类型实现另一种方法:

#include <iostream>
#include <ostream>
#include <sstream>

class MyStream:
    private std::stringbuf,
    public std::ostream
{
public:
    MyStream() noexcept:
        std::stringbuf(),
        std::ostream(this)
    {}

    ~MyStream()
    {
        if (pptr() - pbase() < 2)
        { sync(); }
    }

protected:
    virtual int sync() override
    {
        // make sure there actually is something to sync
        if (pptr() - pbase() < 2)
        { return 0; }

        const std::string message{str()};
        const std::size_t length{message.length()};

        // update the pointers for the next sync
        setp(pbase() + length, epptr());

        std::cout << message;

        return std::stringbuf::sync();
    }
};

MyStream& operator<<(MyStream& out, const char* str)
{
    static_cast<std::ostream&>(out) << str;
    return out;
}

MyStream& operator<<(MyStream& out, bool boolean) noexcept
{ return out << (boolean ? "yes" : "no"); }


int main()
{
    MyStream stream;
    bool b=1;      
    stream << b << " oook " << b << std::endl;    
}



或者,由于MyStream实际ostreamthen 派生的,因此我们可以使用 anyoperator<<作为ostream具有显式强制转换的类型。例如:

#include <iostream>
#include <ostream>
#include <sstream>

class MyStream:
    private std::stringbuf,
    public std::ostream
{
public:
    MyStream() noexcept:
        std::stringbuf(),
        std::ostream(this)
    {}

    ~MyStream()
    {
        if (pptr() - pbase() < 2)
        { sync(); }
    }

protected:
    virtual int sync() override
    {
        // make sure there actually is something to sync
        if (pptr() - pbase() < 2)
        { return 0; }

        const std::string message{str()};
        const std::size_t length{message.length()};

        // update the pointers for the next sync
        setp(pbase() + length, epptr());

        std::cout << message;

        return std::stringbuf::sync();
    }
};

std::ostream& operator<<(MyStream& out, bool boolean) noexcept
{
    return static_cast<std::ostream&>(out) << (boolean ? "yes" : "no");
}

int main()
{
    MyStream stream;
    bool b=1;

    stream << b << " ooOok ";
    stream << b << std::endl;
}

希望输出在哪里:

yes ooOok yes

于 2019-10-21T16:48:18.293 回答