简体   繁体   English

operator<< 的全局重载不起作用,为什么?

[英]Global overload of operator<< does not work, why?

I have learnt the operator<< can be overloaded by making it a friend function of class.我了解到operator<<可以通过使其成为 class 的朋友 function 来重载。 For example,例如,

struct Test
{
    std::string d_data;
    Test(const std::string & data) : d_data{data} {}
    friend std::ostream & operator<<(std::ostream & ostr, const Test & obj)
    {
        ostr << obj.d_data << '\n';
        return ostr;
    }
};

int main()
{
    Test t1("one");
    std::cout << t1;
    Test t2("two");
    std::cout << t2;
}
 one two

This seems to work as expected.这似乎按预期工作。

But, I'm unable to understand why the same isn't working for a global overload.但是,我无法理解为什么同样的方法不适用于全局过载。

#include <iostream>
#include <ostream>
#include <string>

std::ostream & operator<<(std::ostream & os, const std::string & s)
{
    os << s << '\n';
    return os;
}

int main()
{
    std::cout << "stackoverflow";
    std::cout << "stackoverflow";
}

stackoverflowstackoverflow

Expected the strings to be separated by a newline, but didn't work as expected.期望字符串用换行符分隔,但没有按预期工作。

Your operator using您的运营商使用

std::cout << "stackoverflow";

requires a user-defined conversion from an object of the type const char * (after the implicit conversion of the string literal to pointer to its first character) to an object of the type std::string .需要从const char *类型的 object (在将字符串文字隐式转换为指向其第一个字符的指针之后)到std::string类型的 object 的用户定义转换。

However the standard basic_ostream class has already an operator that does not require such a conversion然而,标准 basic_ostream class 已经有一个不需要这种转换的运算符

template<class charT, class traits>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&, const char*);

So this operator is called instead of your operator.所以这个操作符被调用而不是你的操作符。

Moreover within your operator此外,在您的运营商内

std::ostream & operator<<(std::ostream & os, const std::string & s)
{
    os << s << '\n';
    return os;
}

there is recursive calls of itself.有自己的递归调用。

Your could define your operator the following way您可以通过以下方式定义您的运营商

#include <iostream>
#include <string>

std::ostream & operator<<(std::ostream & os, const char *s)
{
    return std::operator <<( os, s ) << '\n';
}

int main()
{
    std::cout << "stackoverflow";
    std::cout << "stackoverflow";
}

and get the expected result并得到预期的结果

stackoverflow
stackoverflow

Note that "stackoverflow" is of type const char[] , but not std::string .请注意, "stackoverflow"const char[]类型,但不是std::string类型。 That means your overload won't be invoked, but the one from standard library ( operator<<(std::basic_ostream) is invoked, because it's an exact match and doesn't require the implicit conversion from const char[] to std::string .这意味着不会调用您的重载,但会调用标准库( operator<<(std::basic_ostream)中的重载,因为它是完全匹配的并且不需要从const char[]std::string

 template< class Traits > basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os, const char* s );

BTW: It could be found because of ADL .顺便说一句:因为ADL可以找到它。

You can overload globally, but "stackoverflow" is not a std::string , so yours isn't used.您可以全局重载,但"stackoverflow"不是std::string ,因此不使用您的。
(And there already is such an overload in the standard library.) (而且标准库中已经存在这样的重载。)

To see that it works, move your first overload out of the class definition and make it a non-friend.要查看它是否有效,请将您的第一个重载移出 class 定义并使其成为非朋友。
The only reason it has to be declared friend is that you have declared it inside the class definition, so it would be a member function otherwise.必须将其声明为friend的唯一原因是您已在 class 定义中声明它,否则它将是成员 function 。

This will work as you expect:这将按您的预期工作:

struct Test
{
    std::string d_data;
    Test(const std::string & data) : d_data{data} {}
};

std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
    ostr << obj.d_data << '\n';
    return ostr;
}

int main()
{
    Test t1("one");
    std::cout << t1;
    Test t2("two");
    std::cout << t2;
}

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

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