简体   繁体   English

自定义 std::ostream 子类中的运算符 << 重载的歧义错误

[英]Ambiguity Errors with operator<< Overloads in custom std::ostream Subclass

While trying to develop a class inheriting from both std::stringbuf and std::ostream and giving it a custom operator<<() overload (which should work for this class, but not for std::ostream in general), I got some ambiguity errors I don't understand.在尝试开发一个继承自std::stringbuf stringbuf 和std::ostream的 class 并为其提供自定义operator<<()重载(这应该适用于这个 class,但不适用于一般的std::ostream )时,我得到了一些我不明白的歧义错误。

The problems are in the bottom half of the following code.问题在以下代码的下半部分。 If I remove the operator<<() overload, I do not get any errors ( g++ --std=c++17 -o foo.exe foo.cpp using g++ 9.2.0, MSYS2 build on Windows).如果我删除operator<<()重载,我不会收到任何错误( g++ --std=c++17 -o foo.exe foo.cpp using g++ 9.2.0, MSYS2 build on 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]
    */
}

Why is my overload for bool a valid candidate for a char* argument?为什么我的bool重载是char*参数的有效候选者? How can I do this properly?我怎样才能正确地做到这一点?

This seems to work for me under linux (g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0):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;
}

I only changed the return call.我只更改了回拨电话。 That's because out << (boolean? "yes": "no") will use the base ostream operator<< for char* types and hence returns a std::basic_ostream<char> type rather than a MyStream return value type.这是因为out << (boolean? "yes": "no")将对char*类型使用基本ostream operator<< ,因此返回std::basic_ostream<char>类型而不是MyStream返回值类型。

And then in main() using a bool type with a MyStream operator<< works:然后在main()中使用带有MyStream operator<<bool类型:

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

..but once the base-class ostream operator<< is invoked for the "Hello World" part of the statement, it of course returns a std::basic_ostream<char> type:) ..但是一旦为语句的"Hello World"部分调用基类ostream operator<< ,它当然会返回std::basic_ostream<char>类型:)

..then after that, because there is no existing ostream operator<< for bool types, the bool b type will get implicitly promoted to a int and so the output is: ..然后在那之后,因为bool类型没有现有的ostream operator<<bool b类型将被隐式提升为int ,因此 output 是:

yesHello World1 ! yesHello World1


Windows builds Windows 构建

But you seemed to be getting other errors.但是您似乎遇到了其他错误。 So while i do not have MSYS2 to hand, i did try to compile the codes on a WinOS with Visual Studio.因此,虽然我手头没有 MSYS2,但我确实尝试使用 Visual Studio 在 WinOS 上编译代码。 In my case, at least, your main() fails immediately due to ambiguities raised by the VS STL implementation:就我而言,至少,由于 VS STL 实现引起的歧义,您的main()立即失败:

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

No need to cast doubt on your current approach as that has already happened in comments.无需对您当前的方法产生怀疑,因为评论中已经发生了这种情况。 but just in an attempt to answer your questions;但只是为了回答您的问题; then one way round would be to implement another operator<< for MyStream that handles char* types:那么一种方法是为处理char*类型的MyStream实现另一个operator<<

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



Alternatively, since MyStream actually is derived from ostream then we can make use of any operator<< for the ostream type with an explicit cast.或者,由于MyStream实际上ostream派生的,因此我们可以使用任何operator<<来表示具有显式强制转换的ostream类型。 For example:例如:

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

where the output is hopefully: output 希望是:

yes ooOok yes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM