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

时间:2019-10-21 12:42:44

标签: c++ stl

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

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

#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*参数的有效候选者?如何正确执行此操作?

1 个答案:

答案 0 :(得分:1)

This 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<<类型不存在bool,因此bool b类型将隐式提升为int,因此输出为:

yesHello World1


Windows构建

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

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



另外,由于ostream实际上是从operator<<衍生而来的,因此我们可以使用显式强制转换将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类型。例如:

model<-Prod.Rate~ lag(Prod.Rate)+Mkt.Rate+Censor
fd<-plm(model, data=FD, model="fd)

希望输出在哪里:

$itemnumber