2

我在使用嵌套枚举的模板参数重载朋友位运算符时遇到了一个问题。

最初我遇到了专有嵌入式 C++ 编译器的问题。之后我尝试了 gcc、clang 和 MSVC 并得到了完全相同的失败。除了,我尝试过的任何 5.0 之前的 GCC 版本都能够编译示例代码。使用任何编译器选择 C++ 标准似乎没有任何区别。

这是一个例子

struct Complex
{
   struct Nested1
   {
       enum ENUM
       {
          Value1_1,
          Value1_2
       };
   };

   struct Nested2
   {
       enum ENUM
       {
          Value2_1,
          Value2_2
       };
   };

   template<typename EnumL, typename EnumR>
   friend Complex operator|(const EnumL dummyL, const EnumR dummyR)
   {
        Complex dummyComplex;
        return dummyComplex;
   }
};

int main()
{
   Complex complex = Complex::Nested1::Value1_1 | Complex::Nested2::Value2_2;
}

编译器看不到运算符 | . 如果我将运算符重载移动到结构定义的下方,代码就会编译。虽然它不再是朋友功能了。

但是,编译稍有不同的代码示例没有任何问题。

struct Complex
{
    enum ENUM1
    {
        Value1_1,
        Value1_2
    };

    enum ENUM2
    {
        Value2_1,
        Value2_2
    };

    template<typename EnumL, typename EnumR>
    friend Complex operator|(const EnumL dummyL, const EnumR dummyR)
    {
        Complex dummyComplex;
        return dummyComplex;
    }
};

int main()
{
   Complex complex = Complex::Value1_1 | Complex::Value2_2;
}

我在这里想念什么?

4

1 回答 1

2

原因是在第一个示例中,operator|不在定义枚举类型的类中。因此, ADL找不到该函数(请参阅该页面第二个列表的第 4 点):

对于枚举类型的参数,将定义枚举类型声明的最内层封闭命名空间添加到集合中。如果枚举类型是类的成员,则将该类添加到集合中。

在上面的引用中,“set”被定义为用于查找函数的“命名空间和类的关联集”。

因此,在第一个示例中,没有operator|找到返回Complex类型。

在第一个示例中,当您将operator|重载移到Complex类之外时,您会将其移到全局命名空间中。全局命名空间始终是上述“集合”的一部分,因此会发现重载。

在第二个示例中,枚举和operator|函数在同一个类中,因此它们被 ADL 找到。

于 2020-10-30T21:41:55.663 回答