一元+
运算符是否只是为了与一元-
运算符对称而被包含在C++中,还是它在C++代码中具有实际用途?
在这里搜索,我发现了C语言中一元'+'运算符的作用是什么?,但那里唯一有用的情况涉及预处理器宏。虽然这些很有用,但它们似乎只是一些不太常见的情况,并且涉及到宏。是否有任何涉及更常见C++代码的用例?
一元+
运算符是否只是为了与一元-
运算符对称而被包含在C++中,还是它在C++代码中具有实际用途?
在这里搜索,我发现了C语言中一元'+'运算符的作用是什么?,但那里唯一有用的情况涉及预处理器宏。虽然这些很有用,但它们似乎只是一些不太常见的情况,并且涉及到宏。是否有任何涉及更常见C++代码的用例?
char ch = 'a';
std::cout << ch << '\n';
std::cout << +ch << '\n';
第一个插入将字符a
写入cout
。第二个插入将ch
的数值写入cout
。但这有点晦涩,它依赖于编译器对+
运算符应用整数提升。
+
与二元+
和<<
的优先级)。 - Greg使用一元的 -
操作符来表达对称性并不完全没有用处;它可以用于强调:
const int foo = -1;
const int bar = +1;
一个过载的一元+
运算符可以用来表示一个操作,它产生与其操作数相同的逻辑值,同时执行一些非平凡的计算。(我曾经见过Ada中使用这种方式进行类型转换,允许重载一元+
,但不允许转换。) 我手头没有一个好的C++示例,而且有人可能会认为这是糟糕的风格。(不过,我见过很多有关重载<<
的抱怨。)
至于C++为什么有它,可能主要是为了与C保持一致,C在1989年的ANSI标准中添加了它。 C Rationale 只是说:
一元加号从几个实现中被C89委员会采纳,以保持与一元减号的对称性。
* this
。@
、$
和 #
。 - Mooing Duck+-*/%=!<>~^|&*.[]()@#$
? - Blacklight Shininga+-b
,那是内置函数还是用户重载? - Mooing Ducka + (-b)
。 :D - Blacklight Shining+
将左值转换为右值:struct A {
static const int value = 1;
};
// ...
int x = std::min(0, A::value);
糟糕!这段代码无法链接,因为有人忘记定义(以及声明)A::value
。std::min
按引用获取其参数,因此A::value
必须具有地址,以便引用可以绑定到它上(从技术上讲,一个定义规则指出它必须在程序中恰好定义一次)。
不过,一元加号来拯救:
int x = std::min(0, +A::value);
一元加号操作符会创建一个临时变量,其值与原变量相同,引用将绑定到临时变量上,因此我们可以通过这种方式规避缺失的定义。
虽然并不经常需要使用该方法,但这是一元加号操作符的实用用途之一。
一元加号应用整数提升。@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 );
}
除了其他事情外,+
还将 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*
在这里也可以工作。但是它们都没有被重载。对我来说,+
更直观,因为它只执行转换,什么都不做。而 *
执行指针转换,然后解引用指针,结果隐式地转换回指针(除非你真的需要一个函数的引用)。 - HolyBlackCat+
运算符可能会很有用(如果可能不是严格必要的)。 请参见this post以获取更深入的讨论。由于算术变量的运算符+会生成一个新值。 我使用它来生成引用类型(代理)的值副本。
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
可能会被误认为是一个类似指针的对象。由于对于算术变量,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
可能会被误认为是类似指针的对象。
return *this;
之外的重载都会被视为滥用。 - rodrigothis
产生副作用,这是否是良好或有用的DSL设计是另一个问题。 - πάντα ῥεῖcout << a & b;
,任何人都可以看出来),这一点就显而易见了。 - rodrigo*this
,还包括通过复制返回它。其次,我发现 operator+ 有更多平凡的用途,特别是对于作为值的引用(代理)的类,而不是值本身。请参见下面的示例。换句话说,operator+ 可能不会完全返回*this
(即“self”),但可以返回具有与“self”“等效”的值的东西。这不是滥用,因为它有一个合理的 operator+,并不是完全实现为return *this;
。 - alfC