【问题标题】:How do I define friends in global namespace within another C++ namespace?如何在另一个 C++ 命名空间内的全局命名空间中定义朋友?
【发布时间】:2011-01-13 12:20:25
【问题描述】:

我想在全局命名空间中定义一个二元运算符。运营商 适用于在另一个命名空间中定义的类,操作员应该得到 访问该类的私有成员。我的问题是我没有 知道如何在类定义中使全局运算符成为朋友时对其进行作用域。

我尝试了类似的方法:

namespace NAME
{
    class A {
        public:
            friend A ::operator * (double lhs, const A& rhs);
        private:
            int private_var;
    };
}

A operator * (double lhs, const A& rhs)
{
    double x = rhs.private_var;
    ...
}

编译器 (g++ 4.4) 不知道如何处理它。好像这条线

friend A ::operator * ()

被评估为类似(伪代码)

(A::operator)

而不是

(A) (::operator)

如果我在运算符的声明中省略 :: 编译工作,但运算符在命名空间 NAME 中,而不是在全局命名空间中。

在这种情况下如何限定全局命名空间?

【问题讨论】:

    标签: c++ namespaces scope friend


    【解决方案1】:

    首先,请注意您的运算符声明缺少 A 的命名空间限定:

    NAME::A operator * (double lhs, const NAME::A& rhs)
    

    然后决定性的技巧是像这样在朋友声明中添加括号,就像您在“伪代码”中提出的那样

    friend A (::operator *) (double lhs, const A& rhs);
    

    为了让它全部编译,你需要一些前向声明,到达这个:

    namespace NAME
    {
        class A;
    }
    
    NAME::A operator * (double lhs, const NAME::A& rhs);
    
    namespace NAME
    {
        class A {
            public:
                friend A (::operator *) (double lhs, const A& rhs);
            private:
                int private_var;
        };
    }
    
    NAME::A operator * (double lhs, const NAME::A& rhs)
    {
        double x = rhs.private_var;
    }
    

    不过,Alexander 是对的——您可能应该在与其参数相同的命名空间中声明运算符。

    【讨论】:

    • 现在有 3 个几乎相同的答案 :-)
    • 当然,你的意思是只有三个:)
    【解决方案2】:

    这是可能的 - 您可以将声明符括在括号中:friend A (::operator * (double lhs, const A& rhs));

    您还需要前向声明类和函数。

    namespace NAME {class A;}
    NAME::A operator *(double lhs, const NAME::A& rhs);
    
    // ...
    
    namespace NAME
    {
        class A {
            public:
                friend A (::operator * (double lhs, const A& rhs));
            private:
                int private_var;
        };
    }
    
    NAME::A operator *(double lhs, const NAME::A& rhs) {
      //...
    }
    

    但我同意 Andreas 的观点,如果可能,最好将两者定义在同一个命名空间中。

    【讨论】:

      【解决方案3】:

      这个编译,我假设没有测试它也可以工作。注意括号的使用:

      namespace NAME {class A; }
      NAME::A operator * (double lhs, const NAME::A& rhs);
      
      namespace NAME
      {
          class A {
              public:
                  friend A (::operator *) (double lhs, const A& rhs);
              private:
                  int private_var;
          };
      }
      
      NAME::A operator * (double lhs, const NAME::A& rhs)
      {
          double x = rhs.private_var;
          return rhs;
      }
      
      int main() {}
      

      不过,正如 Alexander 所提到的,您的问题并没有解释为什么运算符不在命名空间 NAME 中。无论哪种方式,它都可以称为1.0 * some_A_instance。所以你可能会给自己制造不必要的麻烦。

      【讨论】:

      • 该死,你比我早了大约 20 秒。代码也几乎相同。
      • 太好了,你拯救了我的一天。我不知道操作员可以驻留在 NAME 中并且仍然按照我想要的方式工作。
      【解决方案4】:

      我不知道你的问题的确切答案。

      但是在其参数的命名空间之外定义运算符是一个非常糟糕的主意(现在你削减了对运算符非常有用的参数依赖查找)。

      【讨论】:

      • +1。虽然这个答案切入了问题的根源,但有一点点挑剔:如果 op* 在全局范围内,那么您不需要 ADL,因为该功能始终可用。 (我不确定,但也许 OP 不了解 ADL,因此想出了这个?)
      猜你喜欢
      • 2011-01-15
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 2020-12-03
      • 1970-01-01
      • 2018-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多