为什么运营商<<枚举没被使用?

时间:2013-11-05 16:11:57

标签: c++ enums

在下面的代码中,有人可以解释为什么如果启用了“ifdef TEST”分隔的代码,则运算符<<函数我已经定义打印枚举作为字符串不被使用。在我看来,导致我的问题的代码应该与类Container中的枚举打印无关,特别是因为问题代码引用了不同的类(Container2)。

如果我使用g ++ filename.cpp构建,则输出为:

Print for Container: mycolor is red

如果我使用g ++ -DTEST filename.cpp构建,则输出为:

Print for Container: mycolor is 0

代码如下:     #include

namespace mynamespace
{
    enum color {red, blue};
}
namespace mynamespace
{
    class Container
    {
    public:
        mynamespace::color mycolor1;
        explicit Container() : mycolor1(mynamespace::red) {};
        std::ostream &Print(std::ostream& os) const;
    };
    class Container2
    {
    };
}
std::ostream & operator<<(std::ostream &os, const mynamespace::color &_color);

namespace mynamespace
{
#ifdef TEST
// If this is defined, the printing of the enum in Container does not use the operator<< function to output the enum as a string
std::ostream& operator<<(std::ostream &os, const Container2 &i);
#endif
}

int main()
{
    // Create a Container.  Default color is red
    mynamespace::Container *container = new mynamespace::Container;
    container->Print(std::cout);
}

std::ostream & mynamespace::Container::Print(std::ostream &os) const
{
    os << "Print for Container: mycolor is " << mycolor1 << std::endl;
    return os;
}
std::ostream& operator<<(std::ostream &os, const mynamespace::color &_color)
{
    switch(_color)
    {
        case mynamespace::red: os << "red"; break;
        case mynamespace::blue: os << "blue"; break;
        default: os << "unknown"; break;
    }
    return os;
}

2 个答案:

答案 0 :(得分:4)

简化示例:

namespace mynamespace
{
    enum color {red, blue};

    class Container
    {
    public:
        mynamespace::color mycolor1;
        explicit Container() : mycolor1(mynamespace::red) {};
        std::ostream &Print(std::ostream& os) const;
    };
    class Container2
    {
    };

    std::ostream& operator<<(std::ostream &os, const Container2 &i);
}
std::ostream & operator<<(std::ostream &os, const mynamespace::color &_color);

std::ostream & mynamespace::Container::Print(std::ostream &os) const
{
    os << mycolor1 << std::endl;
    return os;
}

表达式os << mycolor1查找名为operator<<的函数。该函数将作为std::ostream的成员函数和(独立地,另外)通过非限定查找搜索,触发ADL。

通过ADL进行的非限定查找将找到mynamespace::operator<<。 “纯”非限定查找(无ADL)将从Print的函数体的范围开始,该范围是类Container(*)的范围,并遍历周围的范围直到找到名为operator<<的函数。然后它停止。在这里,它也停在mynamespace:这是第一个具有该名称的函数的周围范围。未搜索全局命名空间

你可以使“纯粹的”非限定查找找到全局函数,例如说:

std::ostream & mynamespace::Container::Print(std::ostream &os) const
{
    using ::operator<<;
    os << mycolor1 << std::endl;
    return os;
}

(*)您可以将其视为

namespace mynamespace { enum color {red, blue}; class Container2; }

std::ostream& operator<<(std::ostream &os, const mynamespace::color &_color);

namespace mynamespace
{
    std::ostream & operator<<(std::ostream &os, const Container2 &i);

    class Container
    {
    public:
        mynamespace::color mycolor1;
        explicit Container() : mycolor1(mynamespace::red) {};

        std::ostream &Print(std::ostream& os) const
        {
            os << mycolor1 << std::endl;
            return os;
        }
    };
};

在这里,可能更清楚的是,包含名为os << mycolor1的函数的operator<<的第一个周围范围是mynamespace


恕我直言,一个很好的解决方案是将operator<<的枚举mynamespace放在namespace mynamespace { enum color {red, blue}; std::ostream & operator<<(std::ostream &os, const mynamespace::color &_color); } 中:

{{1}}

这样,它可以通过ADL找到。

答案 1 :(得分:1)

注释中提到的问题是命名空间函数隐藏了所有具有相同名称的全局函数; 最简单的解决方案是在fwd声明中添加using语句,如下所示:

namespace mynamespace
{
  using ::operator<<;
  std::ostream& operator<<(std::ostream &os, const Container2 &i);
}

这告诉编译器你没有替换全局范围函数,你只是重载它。