其他运算符

来自cppreference.com
< cpp‎ | language
运算符名 语法 可重载 原型示例(对于 class T
类内定义 类外定义
函数调用 a(a1, a2) R T::operator()(Arg1 &a1, Arg2 &a2, ... ...); N/A
逗号 a, b T2& T::operator,(T2 &b); T2& operator,(const T &a, T2 &b);
条件 a ? b : c N/A N/A

目录

[编辑] 解释

函数调用运算符为任何对象提供函数语义。

条件运算符(口语上称为“三元条件”)检查第一表达式的布尔值,然后取决于结果值,求值并返回第二或第三表达式。

[编辑] 内建的函数调用运算符

函数调用运算符拥有形式

E ( A1, A2, A3,... )

其中

  • E 是指名函数的表达式
  • A1, A2, A3,... 是任意表达式的可能为空的列表,除了不允许逗号运算符在顶层,以避免歧义。

指名函数的表达式能为

a) 指代函数的左值表达式
b) 指向函数指针
c) 选择成员函数的显式类成员访问表达式
d) 隐式成员访问表达式,例如在另一成员函数内使用的成员函数名。

能重载 E 所指代的函数(或成员)名,用重载决议规则决定要调用哪个重载。

E 指定成员函数,则它可为虚,该情况下将以运行时的动态派发,调用该函数的最终覆写者。

为调用函数,

以任意顺序求值表达式 E 还有作为参数提供的所有表达式 A1A2A3 等,它们相对于彼此无顺序

(C++17 前)

表达式 E 先序于表达式 A1A2A3 还有默认参数,若存在。以任意顺序求值参数表达式,它们相对于彼此有非确定顺序

(C++17 起)

若需要,则以隐式转换后的对应实参初始化每个函数形参。若通过成员函数调用,则如同用显式转型到函数所期待的 this 指针一般,转换指向当前对象的 this 指针。每个形参的初始化和析构出现于调用方的语境中,这表明例如若形参的构造函数抛出异常,则不考虑定义于函数内的异常处理块,即使作为函数 try 块。若函数为变参数函数,则应用默认参数提升到省略号形参所匹配的所有实参。形参的生存期结束于定义它于其中的函数返回时,还是外围完整表达式结尾是实现定义的。

函数调用表达式的返回类型是被选择函数的返回类型,以静态绑定决定(忽略 virtual 关键词),即使实际调用的覆写函数返回不同的类型。这允许覆写函数返回引用或指针,并指向从基函数所返回类型派生的类,即 C++ 支持协变返回类型。若 E 指定析构函数,则返回类型为 void

类类型 X 的对象被传递给函数,或被从函数返回时,若 X 的每个复制构造函数、移动构造函数和析构函数均为平凡或被删除,且 X 拥有至少一个未被删除的复制或移动构造函数,则容许实现创建保有函数形参或结果对象的临时对象。

临时对象分别从函数实参或返回值构造,并如同用未被删除的平凡构造函数复制临时量一般,初始化函数形参或返回对象(即使该构造函数无法访问,或要进行对象的赋值或移动的重载决议可能不选择它)。

这允许小的类类型,例如 std::complexstd::span 在寄存器中传递给函数或从函数返回。

(C++17 起)

若函数返回左值引用或到函数的右值引用,则函数调用表达式的值类别为左值,若函数返回到对象的右值引用,则值类别为亡值,否则值类别为纯右值。若函数调用表达式为对象类型纯右值,则它必须拥有完整对象类型,除非在不实质化该纯右值时,例如 (C++17 起)在用作 decltype 的运算数时(或用作作为 decltype 运算数的内建逗号运算符的右运算数时)。

函数调用表达式在语法上类似值初始化 T()函数风格转型表达式 T(A1) 以及临时量的直接初始化 T(A1, A2, A3, ...) ,其中 T 是一个类型的名称。

#include <cstdio>
struct S
{
    int f1(double d) {
        return printf("%f \n", d); // 变参数函数调用
    }
    int f2() {
        return f1(7); // 成员函数调用,同 this->f1()
                      // 整数参数转换为 double
    }
};
void f() {
   puts("function called"); // 函数调用
}
int main()
{
    f(); // 函数调用
    S s;
    s.f2(); // 成员函数调用
}

输出:

function called
7.000000

[编辑] 内建的逗号运算符

逗号运算符表达式拥有形式

E1 , E2

逗号表达式 E1, E2 中,求值 E1舍弃其结果(尽管若它拥有类类型,则在外围完整表达式的结尾前不销毁它),而在表达式 E2 的求值开始前完成其副效应(注意用户定义的 operator, 不能保证定序) (C++17 前)

逗号表达式结果的类型、值和值类别准确地为第二运算数 E2 的类型、值和值类别。若 E2 为临时量表达式 (C++17 起),则表达式的结果为该临时量表达式 (C++17 起)。若 E2 为位域,则结果为位域。

各种逗号分隔列表,例如函数实参列表( f(a, b, c) )和初始化器列表 int a[] = {1,2,3} 中的逗号不是逗号运算符。若需要在这种语境中使用逗号运算符,则必须加括号: f(a, (n++, n+b), c)

#include <iostream>
int main()
{
    int n = 1;
    int m = (++n, std::cout << "n = " << n << '\n', ++n, 2*n);
    std::cout << "m = " << (++m, m) << '\n';
}

输出:

n = 2
m = 7

[编辑] 条件运算符

条件运算符拥有形式

E1 ? E2 : E3

求值条件运算符的第一运算数并将它按语境转换bool 。完成第一运算数的值计算和所有副效应后,若结果为 true ,则求值第二运算数。若结果为 false ,则求值第三运算数。

条件表达式 E1 ? E2 : E3 的类型和值类别按照下列规则确定:

1)E2E3 拥有 void 类型,则下列之一必须为真,否则程序为病式:
1.1) E2E3 (但非两者)为(可有括号的) throw 表达式。则条件运算符拥有另一表达式的类型和值类别。若另一表达式为位域,则结果为位域这种条件运算符常用于 C++14 前的 C++11 constexpr 编程
std::string str = 2+2==4 ? "ok" : throw std::logic_error("2+2 != 4");
1.2) E2E3 都拥有 void 类型(包括两者均为 throw 表达式的情况)。结果为 void 类型纯右值。
2+2==4 ? throw 123 : throw 456;
2) 否则,若 E2E3 是同一值类别的分别为 cv1 T 和 cv2 T 类型的泛左值位域,则此节剩下的部分中认为运算数拥有 cv T 类型,其中 cv 是 cv1 与 cv2 的联合。
(C++14 起)
3) 否则,若 E2E3 拥有不同类型,而至少有一个是(可有 cv 限定的)类类型,或都是同一值类别且拥有除了 cv 限定相同的泛左值,则尝试组成忽略成员访问、运算数是否为位域或转换函数是否被删除的 (C++14 起)隐式转换序列,从每个运算数到另一运算数所确定的描述如下的目标类型。一个 TX 类型运算数(称之为 X )能以如下方式转换成另一 TY 类型运算数(称之为 Y )的目标类型
3.1)Y 为左值,则目标类型为 TY& ,而引用必须直接绑定到左值;
3.2)Y 为亡值,则目标类型为 TY&& ,而引用必须直接绑定;
3.3)Y 为纯右值,或若不能组成任一转换序列,而 TXTY 至少有一个是(可为 cv 限定的)类类型,则目标类型为 Y 在应用左值到右值、数组到指针和函数到指针标准转换后会有的类型。
3.4) 若能组成两个标准序列( E2 到 E3 的目标类型和 E3 到 E2 的目标类型),或只能组成一个但它是有歧义转换序列,则程序为病式。
3.5) 若恰能组成一个转换序列(注意它仍然可能为病式,例如由于访问违规),则应用该转换序列。在此描述的剩余部分(始于 (4) )中用转换后运算数取代原运算数。
3.6) 若不能组成任一转换序列,则在此描述的剩余部分中保留不更改的运算数。
4)E2E3 是同类型和同值类别的泛左值,则结果拥有相同的类型和值类别,而若 E2E3 至少有一个是位域,则结果为位域。
5) 否则,结果为纯右值。若 E2E3 拥有不同类型,且一者拥有(可为 cv 限定的)类类型,则用后面的内建候选,进行尝试转换运算数为内建类型的重载决议。若重载决议失败,则程序为病式。否则,应用选择的转换,并在步骤 6 用转换后运算数取代原运算数。
6) 应用左值到右值、数组到指针和函数到指针转换到第二和第三运算数,然后,
6.1)E2E3 现在拥有相同类型,则结果是该类型的纯右值,其所指代的临时对象 (C++17 前)其结果对象 (C++17 起)从求值 E1 后选择的运算数复制初始化。
6.2)E2E3 拥有算术或枚举类型:则应用通常算术转换将它们变为共用类型,而该类型即是结果。
6.3)E2E3 为指针,或一个是指针而另一个是空指针常量,则应用指针转换和限定转换,将它们变为共用类型,而该类型即是结果。
6.4)E2E3 为指向成员指针,或一个是指针而另一个是空指针常量,则应用指向成员指针转换和限定转换,将它们变成共用类型,而该类型即是结果。
6.5)E2E3 为空指针常量,而至少有一个拥有 std::nullptr_t 类型,则结果类型为 std::nullptr_t
6.6) 所有其他情况下,程序为病式。

对于每对提升后的算术类型 L 和 R 和对于每个类型 P ,其中 P 为指针、指向成员指针或有作用域枚举类型,下列函数签名在上述规则的步骤 5 参与重载决议:

LR operator?:(bool, L, R );
P operator?:(bool, P, P );

其中 LR 是 LR 上进行的通常算术转换的结果。不能重载运算符 “?:” ,这些函数签名只为重载决议的目的存在。

条件运算符的返回类型亦能作为二元类型特性 std::common_type 访问。

#include <string>
#include <iostream>
struct Node
{
    Node* next;
    int data;
    // 深复制的复制构造函数
    Node(const Node& other)
      : next(other.next ? new Node(*other.next) : NULL)
      , data(other.data)
    {}
    Node(int d) : next(NULL), data(d) {}
    ~Node() { delete next ; }
};
int main()
{   
    // 简单的右值示例
    int n = 1 > 2 ? 10 : 11;  // 1 > 2 为 false ,故 n = 11
    // 简单的左值示例
    int m = 10; 
    (n == m ? n : m) = 7; // n == m 为 false ,故 m = 7
    std::cout << "n = " << n << "\nm = " << m; // 输出结果
}

输出:

n = 11
m = 7

[编辑] 标准库

标准库中许多类重载了 operator() ,为了能被用作函数对象。

删除对象或数组
(std::default_delete 的公开成员函数) [编辑]
返回两个实参的和
(std::plus 的公开成员函数) [编辑]
返回两个实参的差
(std::minus 的公开成员函数) [编辑]
返回两个实参的乘积
(std::multiplies 的公开成员函数) [编辑]
返回第一个实参除以第二个实参的结果
(std::divides 的公开成员函数) [编辑]
返回第一个实参除以第二个实参的余数
(std::modulus 的公开成员函数) [编辑]
返回其实参的非
(std::negate 的公开成员函数) [编辑]
检查实参是否相等
(std::equal_to 的公开成员函数) [编辑]
检查实参是否不相等
(std::not_equal_to 的公开成员函数) [编辑]
检查第一个实参是否大于第二个实参
(std::greater 的公开成员函数) [编辑]
检查第一个实参是否小于第二个实参
(std::less 的公开成员函数) [编辑]
检查第一个实参是否大于或等于第二个实参
(std::greater_equal 的公开成员函数) [编辑]
检查第一个实参是否小于或等于第二个实参
(std::less_equal 的公开成员函数) [编辑]
返回两个实参的逻辑 AND
(std::logical_and 的公开成员函数) [编辑]
返回两个实参的逻辑 OR
(std::logical_or 的公开成员函数) [编辑]
返回其实参的逻辑 NOT
(std::logical_not 的公开成员函数) [编辑]
返回两个实参的按位 AND 的结果
(std::bit_and 的公开成员函数) [编辑]
返回两个实参的按位 OR 的结果
(std::bit_or 的公开成员函数) [编辑]
返回两个实参的按位 XOR 的结果
(std::bit_xor 的公开成员函数) [编辑]
返回对其所存储的谓词调用的结果的逻辑补
(std::unary_negate 的公开成员函数) [编辑]
返回对其所存储的谓词的调用的结果的逻辑补
(std::binary_negate 的公开成员函数) [编辑]
调用其所存储的函数
(std::reference_wrapper 的公开成员函数) [编辑]
调用其目标
(std::function 的公开成员函数) [编辑]
用此 locale 的 collate 平面以字典序比较二个字符串
(std::locale 的公开成员函数) [编辑]
比较两个 value_type 类型的值
(std::map::value_compare 的公开成员函数) [编辑]
比较两个 value_type 类型的值
(std::multimap::value_compare 的公开成员函数) [编辑]
执行函数
(std::packaged_task 的公开成员函数) [编辑]
令引擎状态向前并返回生成值
(std::linear_congruential_engine 的公开成员函数) [编辑]
生成分布中的下个随机数
(std::uniform_int_distribution 的公开成员函数) [编辑]

标准库中的任何类都不重载逗号运算符。 boost 库将 operator, 用于 boost.assign 、 boost.spirit 和其他库。数据库访问库 SOCI 亦重载 operator,

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
CWG 1550 C++98 若另一运算数非 void ,则 ?: 中不允许有括号的 throw 表达式 接受有括号的 throw 表达式
CWG 1560 C++98  ?: 中的 void 运算数导致另一运算数上
无理由的左值到右值转换,始终产生右值
带 void 的 ?: 能为左值
CWG 1932 C++14  ?: 中缺失同类型位域 以底层类型处理
CWG 1895 C++14 不明确被删除或不可访问的转换函数是否阻止 ?: 的转换,
且未考虑从基类到派生类纯右值的转换
处理得类似重载决议

[编辑] 参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减
算术 逻辑 比较 成员访问 其他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :

特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型static_castconst_castreinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象,并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)

其他运算符C 文档