【问题标题】:C++0x, user-defined literals with friend operator ""()C++0x,使用友元运算符 ""() 的用户定义文字
【发布时间】:2011-09-09 07:06:23
【问题描述】:

operator "" (...) 定义为友元函数是否可行和/或有用?

class Puzzle {
  friend Puzzle operator "" _puzzle(const char*, size_t);
  ...
};
void solve(Puzzle);
int main() {
  solve("oxo,xox"_puzzle);
};

我正在考虑“有用”,特别是因为operator "" 只能在命名空间中定义的规则——尤其是因为以_ 开头的标识符被保留在全局命名空间中。这是friend 在这里打破这条规则吗?所以,这种不完全的封装不会有任何好处,对吧?

【问题讨论】:

    标签: c++ c++11 friend-function user-defined-literals


    【解决方案1】:

    标准在唯一提到对用户定义文字声明的任何限制的地方直接解决了这个问题,第 13.5.8/2 节:

    declarator-id 为 literal-operator-id 的声明应是命名空间范围函数或函数模板的声明(它可以是友元函数 (11.3)),显式函数模板的实例化或特化,或使用声明 (7.3.3)。

    如果朋友也在命名空间范围内声明,那么在类或命名空间范围内的定义没有区别。请注意,在命名空间范围内没有定义要求,您的问题当前措辞断言。

    如果未在命名空间范围内声明,由于 ADL 无法找到它,因此可以通过常规非限定名称查找在其所在范围内的类中私下使用友元。这是声明不是外部接口的文字运算符的唯一方法。

    如果友元是在类模板中定义的,那么模板的两个实例化将在命名空间范围内生成两个同名函数,即使它们在类范围之外都是不可见的,它们也会发生冲突。

    【讨论】:

    • 我真的以为我在某处读过它,后缀应该只能在命名空间中声明。我不记得在哪里——但这只是一个建议,而不是要求。因此,这可能是“良好实践”的唯一提示。关于 template 友元函数的要点。这不是通常的 friend 模式的问题,至少有一个朋友函数的参数是类实例本身——那么就不存在命名问题。
    • 我记得在早期的立场文件中看到过类似的内容。试试 n2378.pdf 第 5 节:成语。这里他们说: 1. 当通过文字而不是显式运算符形式调用时,这些函数无法通过 ADL 找到。 2. 这将吸引在全球的布局。 3. 即使在不使用文字的代码中,这也会导致冲突。 4. 所以把文字操作放在一个命名空间中,并放置一个 using 指令将它们拉到全局级别。
    • 我只是想指出,您可以在课堂内私下使用朋友功能,请参阅this question
    【解决方案2】:

    如果它对语法有帮助,下面是我如何在类中声明朋友用户定义的文字运算符,其中运算符本身位于命名空间中:

    class Integer;
    namespace literals {
      Integer operator "" _I (const char *);
    }
    
    // Infinite precision integer 
    class Integer {
      public:
    
      // Basic constructor & destructor
       Integer ();
      ~Integer ();
    
    ... rest of the interface ...
    
      // Literal operator
      friend Integer literals::operator "" _I (const char *);
    
      private:
    
      struct Detail;
      std::unique_ptr<Detail> detail;
    
    };
    

    用户仅在需要时才使用using namespace literals; 语句引入运算符。 (实际上,所有这些都在父命名空间中,但你明白了)。

    【讨论】:

      【解决方案3】:

      按照标准,是的,朋友声明应该是合法的。 顺便说一句,这个名字对于用户代码来说很好,因为它以一个下划线开头,即使在全局命名空间中也是如此。

      friend 声明将允许操作员访问类私有数据。

      我开始质疑友元文字运算符的用处。因为用户定义的运算符只能有几个参数列表,所以无法将类放在参数中。所以现在有一种方法可以让参数相关的查找找到正确的函数。我说的对吗?

      【讨论】:

      • 我认为可以使用 ADL,但它必须寻找 const char* 参数或任何您定义的运算符。但无论如何,我也怀疑它的用处:好的,您可以访问私有数据,但无论如何您都需要调用构造函数。顺便说一句:johannes(其他回答 cmets)指出,名称不是_puzzle,而是operator "" _puzzle,因此不会以下划线开头。
      • 是的,根据 13.5.8/7,常规查找将优先于文字运算符。我得到名字的问题。我挂断了 17.6.4.3.5,它保留了文字后缀 没有 用于实现的前导下划线。
      • 我认为他们设计的主要目的是他们将允许仅库实现,例如十进制。用户定义的文字运算符提供了一个进入词法分析器的钩子。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多