【问题标题】:Does the unary + operator have any practical use?一元 + 运算符有什么实际用途吗?
【发布时间】:2012-12-31 04:54:01
【问题描述】:

一元 + 运算符是为了与一元 - 运算符对称而包含的,还是在 C++ 代码中找到了一些实际用途?

在这里搜索,我遇到了What is the purpose of the unary '+' operator in C?,但那里唯一有用的场景涉及预处理器宏。这些很高兴知道,但它们似乎是一些不太常见的情况,并且涉及宏。有没有涉及更常见的 C++ 代码的用例?

【问题讨论】:

  • 数学?不,但它可能会在使用类的运算符重载中找到用途。
  • @ValekHalfHeart:是的,但是除了return *this; 之外的任何重载都将被视为滥用。
  • @rodrigo 但仍然会对this 产生副作用,不是吗?如果这是好的或有用的 DSL 设计是另一个问题。
  • @ArneMertz:尽管 Boost.Spirit 很好,但它肯定是一种语言滥用。并不是说它有任何优点,但是运算符重载并不是为了做这种事情而设计的,因为当您意识到您无法更改运算符优先级并且您对旧运算符的花哨的新含义有点松散时,这一点很明显(@ 987654326@,有人吗?)。
  • @ApproachingDarknessFish:它可能会在类的运算符重载中找到用途。你能举个例子来解释一下吗?

标签: c++ operators unary-operator


【解决方案1】:

由于算术变量 operator+ 生成一个 new 值, 我通常使用它来生成类引用(代理)类型的值副本。

template<class T> class ref_of{
   T* impl_; // or a more complicated implementation
public:
   T operator+() const{return *impl_;} 
   operator T&()&{return *impl_;}
}
...
ref_of<T> r = t;
auto s = +r; // this forces a copy

另一种选择是使用operator*,但ref_of 可能会与类似指针的对象混淆。

【讨论】:

    【解决方案2】:

    除其他外,+ 将 lambda 转换为函数指针。通常转换会自动发生,但有时不会。

    例如,这不会编译:

    std::array arr{
        [](int x){return x*x;},
        [](int x){return x*x*x;},
    };
    

    您可以通过将函数指针类型指定为std::array 模板参数来使其工作,您可以这样做:

    std::array arr{
        +[](int x){return x*x;},
        +[](int x){return x*x*x;},
    };
    

    【讨论】:

    • 有什么理由更喜欢重载的 operator+ 函数而不是 operator* 用于这个特定目的?我不明白为什么 operator+ 在需要函数指针时被认为是更直观的选择。
    • @303 有趣的是,我从未想过* 也在这里工作。但它们都没有超载。 + 对我来说看起来更直观,因为它只执行转换,没有别的。而* 执行到指针的转换,然后取消引用指针,然后将结果隐式转换回指针(除非您确实需要对函数的引用)。
    【解决方案3】:

    由于算术变量 operator+ 生成一个新值。 我用它来生成类引用(代理)类型的值副本。

    template<class T> class ref_of{
       T* impl_; // or a more complicated implementation
    public:
       T operator+() const{return *impl_;}
       operator T&()&{return *impl_;}
    }
    

    另一种选择是使用operator*,但ref_of 可能会与类似指针的对象混淆。

    【讨论】:

      【解决方案4】:

      有点晚了,但这是我偶然发现的一个非常扭曲的用法。显然,+ 运算符在围绕遇到空预处理器令牌的可能性设计安全措施时可能很有用(如果可能不是绝对必要的话)。请参阅this post 进行更深入的讨论。

      这很实用,但绝不是令人愉快的。

      【讨论】:

        【解决方案5】:

        一元+ 运算符将左值转换为右值:

        struct A {
          static const int value = 1;
        };
        
        // ...
        
        int x = std::min(0, A::value);
        

        哦,不!此代码不会链接,因为有人忘记定义(以及声明)A::valuestd::min 通过引用获取其参数,因此 A::value 必须有一个地址,以便引用可以绑定到它(从技术上讲,一个定义规则说它必须在程序中只定义一次。)

        没关系,一元加号:

        int x = std::min(0, +A::value);
        

        一元加号创建一个具有相同值的临时对象,并且引用绑定到该临时对象,因此我们可以解决缺少的定义。

        这不是你经常需要的东西,但它是一元加号运算符的实际用途。

        【讨论】:

          【解决方案6】:

          一元 + 应用积分促销。 @PeteBecker 的回答显示了一种有用的方法。

          另外,请注意,无范围枚举类型被提升为整数类型,可以表示enum 中的所有值。所以在 C++03 中,即使没有 C++11 的 std::underlying_type&lt;T&gt;,你也可以这样做:

          enum MyBitMask {
              Flag1 = 0x1,
              Flag2 = 0x2,
              Flag3 = 0x4,
              Flag4 = 0x8000000
          };
          
          inline MyBitMask operator&(MyBitMask x, MyBitMask y) {
              return static_cast<MyBitMask>( +x & +y );
          }
          
          inline MyBitMask operator|(MyBitMask x, MyBitMask y) {
              return static_cast<MyBitMask>( +x | +y );
          }
          

          【讨论】:

            【解决方案7】:
            char ch = 'a';
            std::cout << ch << '\n';
            std::cout << +ch << '\n';
            

            第一个插入将字符a 写入cout。第二次插入将ch 的数值写入cout。但这有点晦涩难懂。它依赖于编译器为 + 运算符应用积分提升。

            【讨论】:

            • 数值是否与 ASCII 等价?
            • @David - 使用 ASCII 的编译器,是的。对于其他编码(很少见),没有。
            • 似乎对我不起作用 -- stacked-crooked.com/view?id=235071220bc8ba0e688b4b58051e182d 这些可能是罕见的编码吗?
            • @David - 不知道你的程序发生了什么,但 104 是 'h' 的 ASCII 码。哦,对不起,我发现我的代码中有一个错误,我刚刚修复了它。希望这不会让您感到困惑。
            【解决方案8】:

            如果您明确地避免类的任何数值语义,则 any 运算符重载显然不会“像整数那样做”。在这种情况下,一元加号可能有任何意义,不仅仅是返回 *this

            突出示例:嵌入式 EBNF 的 Boost.Spirit's unary plusKleene Plus 生成一个解析器规则,使其参数(也是解析器规则)匹配一次或多次。

            【讨论】:

            • 我希望我们也可以超载 @$#
            • @MooingDuck 当你在做的时候,我们是否有能力使用+-*/%=!&lt;&gt;~^|&amp;*.[]()@#$ 的任意组合来制作我们自己的运算符?
            • 其中大多数会使解析模棱两可。如果编译器看到a+-b,是内置函数还是用户重载?
            • @MooingDuck 如果存在这样的重载,那就是重载;否则它是a + (-b)。 :D
            【解决方案9】:

            一元 - 的对称性并非完全没用;可用于强调:

            const int foo = -1;
            const int bar = +1;
            

            重载一元+ 可用于表示产生与其操作数相同的逻辑值的操作,同时执行一些非平凡的计算。 (我已经看到 Ada 中的类型转换这样做了,它允许重载一元 +,但不允许转换。)我手头没有一个好的 C++ 示例,有人可能会争辩说它会很差风格。 (话又说回来,我看到很多关于超载&lt;&lt; 的咆哮。)

            至于为什么 C++ 有它,可能很大程度上是为了与 C 保持一致,C 将它添加到 1989 年的 ANSI 标准中。 C Rationale 只是说:

            一元加号被 C89 委员会从几个 实现,与一元减号对称。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-23
              • 2011-05-06
              • 2018-08-07
              • 2011-04-25
              • 2011-10-17
              • 2021-07-01
              相关资源
              最近更新 更多