30

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

在这里搜索,我遇到了C中一元'+'运算符的目的是什么?,但唯一有用的场景涉及预处理器宏。这些很高兴知道,但它们似乎是一些不太常见的情况,并且涉及宏。是否有涉及更常见 C++ 代码的用例?

4

9 回答 9

33
char ch = 'a';
std::cout << ch << '\n';
std::cout << +ch << '\n';

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

于 2013-01-16T19:07:27.043 回答
21

一元对称-并非完全没用。它可以用于强调:

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

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

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

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

于 2013-01-16T19:07:41.400 回答
11

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

突出的例子:Boost.Spirit 的一元加法用于嵌入式 EBNF 的Kleene Plus生成一个解析器规则,让它的参数(也是一个解析器规则)匹配一次或多次。

于 2013-01-16T19:17:25.070 回答
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);

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

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

于 2013-03-05T23:25:08.577 回答
3

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

另一方面,请注意,一个无作用域的枚举类型被提升为一个整数类型,它可以表示enum. 所以在 C++03 中,即使没有 C++11 std::underlying_type<T>,你也可以这样做:

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 );
}
于 2013-01-18T22:04:00.307 回答
1

有点晚了,但这是我偶然发现的一个非常扭曲的用法。显然,在+围绕遇到空预处理器令牌的可能性设计安全措施时,操作员可能很有用(如果可能不是严格必要的话)。有关更深入的讨论,请参阅此帖子。

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

于 2014-01-20T01:30:52.697 回答
1

除其他外,+将 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;},
};
于 2020-08-30T11:10:16.457 回答
0

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

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可能会与类似指针的对象混淆。

于 2020-08-30T12:06:23.920 回答
0

因为对于算术变量 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可能会与类似指针的对象混淆。

于 2020-08-30T10:57:50.923 回答