名前空間
変種
操作

算術演算子

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

特定の算術演算の結果を返します。

演算子名 構文 プロトタイプの例 (class T の場合)
クラス定義内 クラス定義外
単項プラス +a T T::operator+() const; T operator+(const T& a);
単項マイナス -a T T::operator-() const; T operator-(const T& a);
加算 a + b T T::operator+(const T2& b) const; T operator+(const T& a, const T2& b);
減算 a - b T T::operator-(const T2& b) const; T operator-(const T& a, const T2& b);
乗算 a * b T T::operator*(const T2& b) const; T operator*(const T& a, const T2& b);
除算 a / b T T::operator/(const T2& b) const; T operator/(const T& a, const T2& b);
剰余 a % b T T::operator%(const T2& b) const; T operator%(const T& a, const T2& b);
ビット単位NOT ~a T T::operator~() const; T operator~(const T& a);
ビット単位AND a & b T T::operator&(const T2& b) const; T operator&(const T& a, const T2& b);
ビット単位OR a | b T T::operator|(const T2& b) const; T operator|(const T& a, const T2& b);
ビット単位XOR a ^ b T T::operator^(const T2& b) const; T operator^(const T& a, const T2& b);
ビット単位左シフト a << b T T::operator<<(const T2& b) const; T operator<<(const T& a, const T2& b);
ビット単位右シフト a >> b T T::operator>>(const T2& b) const; T operator>>(const T& a, const T2& b);
注釈
  • この表のすべての演算子はオーバーロード可能です。
  • すべての組み込み演算子は値を返し、ほとんどのユーザー定義オーバーロードも値を返すため、ユーザー定義演算子も組み込み演算子と同様に使用できます。ただし、ユーザー定義演算子のオーバーロードでは、任意の型を戻り値の型として使用できます(voidを含む)。特に、ストリーム挿入およびストリーム抽出演算子operator<<およびoperator>>のオーバーロードはT&を返します。
  • T2Tを含む任意の型であることができます。

目次

[編集] 一般説明

すべての組み込み算術演算子は、特定の算術演算の結果を計算し、その結果を返します。引数は変更されません。

[編集] 変換

組み込み算術演算子に渡されるオペランドが整数型またはスコープなし列挙型の場合、他の処理の前に(ただし、lvalue-to-rvalue変換が適用される場合はその後)整数昇格が行われます。オペランドが配列型または関数型の場合、配列からポインタへの変換関数からポインタへの変換が適用されます。

二項演算子(シフトを除く)の場合、昇格されたオペランドの型が異なる場合、通常の算術変換が適用されます。

[編集] オーバーフロー

符号なし整数の算術演算は常に2nを法として実行されます。ここで n はその特定の整数のビット数です。例えば、unsigned intの場合、UINT_MAXに1を加えると0になり、0から1を引くとUINT_MAXになります。

符号付き整数の算術演算がオーバーフローした場合(結果が結果の型に収まらない場合)、動作は未定義です。このような演算の考えられる現れ方としては、

  • 表現規則に従ってラップアラウンドする(通常は2の補数)、
  • トラップする — 一部のプラットフォームまたはコンパイラオプション(例: GCCおよびClangの-ftrapv)により、
  • 最小値または最大値に飽和する(多くのDSPの場合)、
  • コンパイラによって完全に最適化されてしまう

[編集] 浮動小数点環境

#pragma STDC FENV_ACCESS がサポートされており ON に設定されている場合、すべての浮動小数点算術演算子は現在の浮動小数点丸め方向に従い、静的初期化子の一部でない限り(この場合、浮動小数点例外は発生せず、丸めモードは最近接丸めになります)、math_errhandlingで指定された浮動小数点算術エラーを報告します。

[編集] 浮動小数点縮約

#pragma STDC FP_CONTRACT がサポートされ、OFF に設定されていない限り、すべての浮動小数点演算は、中間結果が無限の範囲と精度を持つかのように実行される可能性があります。つまり、丸め誤差や浮動小数点例外を省略する最適化が許可されます。例えば、C++では(x * y) + zを単一の積和演算CPU命令で実装したり、a = x * x * x * x;tmp = x * x; a = tmp * tmpとして最適化したりすることができます。

縮約とは無関係に、浮動小数点演算の中間結果は、その型によって示されるものとは異なる範囲と精度を持つ可能性があります。詳細はFLT_EVAL_METHODを参照してください。

形式的には、C++標準は浮動小数点演算の精度に関して何の保証もしていません。

[編集] 単項算術演算子

単項算術演算子の式は以下の形式をとります。

+ expression (1)
- expression (2)
1) 単項プラス (昇格)。
2) 単項マイナス (否定)。

単項+および-演算子は、すべての二項算術演算子よりも高い優先順位を持つため、expressionはトップレベルの二項算術演算子を含むことはできません。これらの演算子は右から左へ結合します。

+a - b; // equivalent to (+a) - b, NOT +(a - b)
-c + d; // equivalent to (-c) + d, NOT -(c + d)
 
+-e; // equivalent to +(-e), the unary + is a no-op if “e” is a built-in type
     // because any possible promotion is performed during negation already

[編集] 組み込み単項算術演算子

1) 組み込み単項プラス演算子の場合、expressionは算術型、スコープなし列挙型、またはポインタ型のprvalueでなければなりません。もしexpressionが整数型またはスコープなし列挙型である場合、整数昇格が実行されます。結果の型は、expressionの(昇格された可能性のある)型です。
組み込み昇格の結果はexpressionの値です。オペランドが昇格された整数型またはポインタ型のprvalueである場合、組み込み単項演算はno-opです。それ以外の場合、オペランドの型または値カテゴリは、整数昇格、lvalue-to-rvalue、配列-to-ポインタ、関数-to-ポインタ、またはユーザー定義変換によって変更されます。例えば、charintに変換され、非総称的なキャプチャレスラムダ式は関数ポインタに変換されます(C++11以降)、単項プラス式では。
2) 組み込み単項マイナス演算子の場合、expressionは算術型またはスコープなし列挙型のprvalueでなければなりません。expressionに対して整数昇格が実行されます。結果の型は、expressionの昇格された型の型です。
組み込み否定の結果は、昇格されたexpressionの負の値です。符号なしaの場合、-aの値は2N-aです。ここで、Nは昇格後のビット数です。
  • 言い換えれば、結果はオペランドの2の補数です(オペランドと結果は符号なしとみなされます)。

[編集] オーバーロード

ユーザー定義演算子のオーバーロード解決において、すべてのcv修飾なし昇格算術型Aとすべての型Tについて、以下の関数シグネチャがオーバーロード解決に参加します。

A operator+(A)
T* operator+(T*)
A operator-(A)
#include <iostream>
 
int main()
{
    char c = 0x6a;
    int n1 = 1;
    unsigned char n2 = 1;
    unsigned int n3 = 1;
    std::cout << "char: " << c << " int: " << +c << "\n"
                 "-1, where 1 is signed: " << -n1 << "\n"
                 "-1, where 1 is unsigned char: " << -n2 << "\n"
                 "-1, where 1 is unsigned int: " << -n3 << '\n';
    char a[3];
    std::cout << "size of array: " << sizeof a << "\n"
                 "size of pointer: " << sizeof +a << '\n';
}

実行結果の例

char: j int: 106
-1, where 1 is signed: -1
-1, where 1 is unsigned char: -1
-1, where 1 is unsigned int: 4294967295
size of array: 3
size of pointer: 8

[編集] 加算演算子

加算演算子の式は以下の形式をとります。

lhs + rhs (1)
lhs - rhs (2)
1) 二項プラス (加算)。
2) 二項マイナス (減算)。

二項+および-演算子は、*/%以外のすべての二項算術演算子よりも高い優先順位を持ちます。これらの演算子は左から右へ結合します。

a + b * c;  // equivalent to a + (b * c),  NOT (a + b) * c
d / e - f;  // equivalent to (d / e) - f,  NOT d / (e - f)
g + h >> i; // equivalent to (g + h) >> i, NOT g + (h >> i)
 
j - k + l - m; // equivalent to ((j - k) + l) - m

[編集] 組み込み加算演算子

組み込みの二項プラスおよび二項マイナス演算子の場合、lhsrhsの両方がprvalueであり、以下のいずれかの条件を満たす必要があります。

  • 両方のオペランドが算術型またはスコープなし列挙型である。この場合、両方のオペランドに対して通常の算術変換が実行されます。
  • ちょうど1つのオペランドが整数型またはスコープなし列挙型である。この場合、そのオペランドに対して整数昇格が適用されます。

このセクションの残りの説明では、「オペランド」、「lhs」、「rhs」は変換または昇格されたオペランドを指します。

1) 組み込みの加算の場合、以下のいずれかの条件を満たす必要があります。
  • 両方のオペランドが算術型である。この場合、結果はオペランドの合計です。
  • 一方のオペランドが完全に定義されたオブジェクト型へのポインタであり、もう一方のオペランドが整数型である。この場合、整数値がポインタに加算されます(ポインタ演算を参照)。
2) 組み込みの減算の場合、以下のいずれかの条件を満たす必要があります。
  • 両方のオペランドが算術型である。この場合、結果はlhsからrhsを減算した結果の差です。
  • lhsが完全に定義されたオブジェクト型へのポインタであり、rhsが整数型である。この場合、整数値がポインタから減算されます(ポインタ演算を参照)。
  • 両方のオペランドが同じ完全に定義されたオブジェクト型のcv修飾版またはcv修飾なし版へのポインタである。この場合、lhsからrhsが減算されます(ポインタ演算を参照)。

両方のオペランドが浮動小数点型であり、その型がIEEE浮動小数点演算をサポートしている場合(std::numeric_limits::is_iec559を参照)

  • 一方のオペランドがNaNの場合、結果はNaNです。
  • 無限大から無限大を引くとNaNになり、FE_INVALIDが設定されます。
  • 無限大に負の無限大を加えるとNaNになり、FE_INVALIDが設定されます。

[編集] ポインタ演算

整数型を持つ式Jがポインタ型を持つ式Pに加算または減算されると、結果はPの型を持ちます。

  • もしPヌルポインタ値に評価され、J0に評価される場合、結果はヌルポインタ値になります。
  • それ以外の場合、Pn個の要素を持つ配列オブジェクトxi番目の要素を指し、Jの値がjである場合、Pは次のように加算または減算されます。
  • P + JJ + Pは、
  • i + j[0n)の範囲内にある場合、xi+j番目の要素を指し、
  • i + jnである場合、xの最後の要素の終端を超えるポインタとなります。
  • P - Jは、
  • i - j[0n)の範囲内にある場合、xi-j番目の要素を指し、
  • i - jnである場合、xの最後の要素の終端を超えるポインタとなります。
  • その他のjの値は未定義動作となります。
  • それ以外の場合、Pが完全なオブジェクト、基底クラスのサブオブジェクト、またはメンバサブオブジェクトyを指し、Jの値がjである場合、Pは次のように加算または減算されます。
  • P + JJ + Pは、
  • j0である場合、yを指し、
  • j1である場合、yの終端を超えるポインタとなります。
  • P - Jは、
  • j0である場合、yを指し、
  • j-1である場合、yの終端を超えるポインタとなります。
  • その他のjの値は未定義動作となります。
  • それ以外の場合、Pがオブジェクトzの終端を超えるポインタであり、Jの値がjである場合、
  • もしzn個の要素を持つ配列オブジェクトである場合、Pは次のように加算または減算されます。
  • P + JJ + Pは、
  • n + j[0n)の範囲内にある場合、zn+j番目の要素を指し、
  • j0である場合、zの最後の要素の終端を超えるポインタとなります。
  • P - Jは、
  • n - j[0n)の範囲内にある場合、zn-j番目の要素を指し、
  • j0である場合、zの最後の要素の終端を超えるポインタとなります。
  • その他のjの値は未定義動作となります。
  • それ以外の場合、Pは次のように加算または減算されます。
  • P + JJ + Pは、
  • j-1である場合、zを指し、
  • j0である場合、zの終端を超えるポインタとなります。
  • P - Jは、
  • j1である場合、zを指し、
  • j0である場合、zの終端を超えるポインタとなります。
  • その他のjの値は未定義動作となります。
  • それ以外の場合、動作は未定義です。

2つのポインタ式PQが減算される場合、結果の型はstd::ptrdiff_tです。

  • もしPQの両方がヌルポインタ値に評価される場合、結果は0です。
  • それ以外の場合、PQがそれぞれ同じ配列オブジェクトxi番目とj番目の配列要素を指す場合、式P - Qの値はi − jです。
  • もしi − jstd::ptrdiff_tで表現できない場合、動作は未定義です。
  • それ以外の場合、PQが同じ完全なオブジェクト、基底クラスのサブオブジェクト、またはメンバサブオブジェクトを指す場合、結果は0です。
  • それ以外の場合、動作は未定義です。

これらのポインタ算術演算子は、ポインタがLegacyRandomAccessIterator要件を満たすことを可能にします。

加算と減算の場合、もしPまたはQが「(おそらくcv修飾された)Tへのポインタ」型であり、Tと配列要素型が類似でない場合、動作は未定義です。

int arr[5] = {1, 2, 3, 4, 5};
unsigned int *p = reinterpret_cast<unsigned int*>(arr + 1);
unsigned int k = *p; // OK, the value of “k” is 2
unsigned int *q = p + 1; // undefined behavior: “p” points to int, not unsigned int

[編集] オーバーロード

ユーザー定義演算子のオーバーロード解決において、昇格された算術型LRのすべてのペアおよびすべてのオブジェクト型Tについて、以下の関数シグネチャがオーバーロード解決に参加します。

LR operator+(L, R)
LR operator-(L, R)
T* operator+(T*, std::ptrdiff_t)
T* operator+(std::ptrdiff_t, T*)
T* operator-(T*, std::ptrdiff_t)
std::ptrdiff_t operator-(T*, T*)

ここで、LRLRに対する通常の算術変換の結果です。

#include <iostream>
 
int main()
{
    char c = 2;
    unsigned int un = 2;
    int n = -10;
    std::cout << " 2 + (-10), where 2 is a char    = " << c + n << "\n"
                 " 2 + (-10), where 2 is unsigned  = " << un + n << "\n"
                 " -10 - 2.12  = " << n - 2.12 << '\n';
 
    char a[4] = {'a', 'b', 'c', 'd'};
    char* p = &a[1];
    std::cout << "Pointer addition examples: " << *p << *(p + 2)
              << *(2 + p) << *(p - 1) << '\n';
    char* p2 = &a[4];
    std::cout << "Pointer difference: " << p2 - p << '\n';
}

出力

 2 + (-10), where 2 is a char    = -8
 2 + (-10), where 2 is unsigned  = 4294967288
 -10 - 2.12  = -12.12
Pointer addition examples: bdda
Pointer difference: 3

[編集] 乗算演算子

乗算演算子の式は以下の形式をとります。

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (3)
1) 乗算。
2) 除算。
3) 剰余。

乗算演算子は、他のすべての二項算術演算子よりも高い優先順位を持ちます。これらの演算子は左から右へ結合します。

a + b * c;  // equivalent to a + (b * c),  NOT (a + b) * c
d / e - f;  // equivalent to (d / e) - f,  NOT d / (e - f)
g % h >> i; // equivalent to (g % h) >> i, NOT g % (h >> i)
 
j * k / l % m; // equivalent to ((j * k) / l) % m

[編集] 組み込み乗算演算子

組み込み乗算および除算演算子の場合、両方のオペランドは算術型またはスコープなし列挙型である必要があります。組み込み剰余演算子の場合、両方のオペランドは整数型またはスコープなし列挙型である必要があります。通常の算術変換が両方のオペランドに対して実行されます。

このセクションの残りの説明では、「オペランド」、「lhs」、「rhs」は変換されたオペランドを指します。

1) 組み込み乗算の結果はオペランドの積です。
両方のオペランドが浮動小数点型であり、その型がIEEE浮動小数点演算をサポートしている場合(std::numeric_limits::is_iec559を参照)
  • NaNに任意の数を乗算するとNaNになります。
  • 無限大にゼロを乗算するとNaNになり、FE_INVALIDが設定されます。
2) 組み込み除算の結果はlhsrhsで割ったものです。rhsがゼロの場合、動作は未定義です。
両方のオペランドが整数型である場合、結果は代数商です(整数除算を実行します):商はゼロに向かって切り捨てられます(小数部分は破棄されます)。
両方のオペランドが浮動小数点型であり、その型がIEEE浮動小数点演算をサポートしている場合(std::numeric_limits::is_iec559を参照)
  • 一方のオペランドがNaNの場合、結果はNaNです。
  • ゼロでない数を±0.0で割ると、正しい符号の無限大になり、FE_DIVBYZEROが設定されます。
  • 0.0を0.0で割るとNaNになり、FE_INVALIDが設定されます。
3) 組み込み剰余の結果は、lhsrhsで整数除算した余りです。rhsがゼロの場合、動作は未定義です。
もしa / bが結果の型で表現可能であれば、(a / b) * b + a % b == aです。
もしa / bが結果の型で表現できない場合、a / ba % bの両方の動作は未定義です(これは、2の補数システムではINT_MIN % -1が未定義であることを意味します)。

注: CWG issue 614が解決されるまで(N2757)、二項演算子%のオペランドが1つ以上負の場合、剰余の符号は整数除算の丸め方向によって実装定義でした。この場合、関数std::divは明確な動作を提供しました。

注: 浮動小数点剰余については、std::remainderおよびstd::fmodを参照してください。

[編集] オーバーロード

ユーザー定義演算子のオーバーロード解決において、昇格された算術型LARAのすべてのペア、および昇格された整数型LIRIのすべてのペアについて、以下の関数シグネチャがオーバーロード解決に参加します。

LRA operator*(LA, RA)
LRA operator/(LA, RA)
LRI operator%(LI, RI)

ここで、LRxLxRxに対する通常の算術変換の結果です。

#include <iostream>
 
int main()
{
    char c = 2;
    unsigned int un = 2;
    int  n = -10;
    std::cout << "2 * (-10), where 2 is a char    = " << c * n << "\n"
                 "2 * (-10), where 2 is unsigned  = " << un * n << "\n"
                 "-10 / 2.12  = " << n / 2.12 << "\n"
                 "-10 / 21  = " << n / 21 << "\n"
                 "-10 % 21  = " << n % 21 << '\n';
}

出力

2 * (-10), where 2 is a char    = -20
2 * (-10), where 2 is unsigned  = 4294967276
-10 / 2.12  = -4.71698
-10 / 21  = 0
-10 % 21  = -10

[編集] ビット単位論理演算子

ビット単位論理演算子の式は以下の形式をとります。

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) ビット単位NOT。
2) ビット単位AND。
3) ビット単位OR。
4) ビット単位XOR。

ビット単位NOT演算子は、すべての二項算術演算子よりも高い優先順位を持ちます。右から左へ結合します。

~a - b; // equivalent to (~a) - b, NOT ~(a - b)
~c * d; // equivalent to (~c) * d, NOT ~(c * d)
 
~-e; // equivalent to ~(-e)

~の後に型名またはdecltype指定子(C++11以降)が続く場合、文法上の曖昧さがあります。これは、operator~であるか、デストラクタ識別子の開始であるかのいずれかです。この曖昧さは、~をoperator~として扱うことで解決されます。~がデストラクタ識別子を開始できるのは、operator~を形成することが構文的に無効な場所に限られます。

他のすべてのビット単位論理演算子は、他のすべての二項算術演算子よりも低い優先順位を持ちます。ビット単位ANDはビット単位XORよりも優先順位が高く、ビット単位XORはビット単位ORよりも優先順位が高いです。これらは左から右へ結合します。

a & b * c;  // equivalent to a & (b * c),  NOT (a & b) * c
d / e ^ f;  // equivalent to (d / e) ^ f,  NOT d / (e ^ f)
g << h | i; // equivalent to (g << h) | i, NOT g << (h | i)
 
j & k & l; // equivalent to (j & k) & l
m | n ^ o  // equivalent to m | (n ^ o)

[編集] 組み込みビット単位論理演算子

組み込みビット単位NOT演算子の場合、rhsは整数型またはスコープなし列挙型のprvalueでなければならず、rhsに対して整数昇格が実行されます。他の組み込みビット単位論理演算子の場合、両方のオペランドは整数型またはスコープなし列挙型でなければならず、両方のオペランドに対して通常の算術変換が実行されます。

このセクションの残りの説明では、「オペランド」、「lhs」、「rhs」は変換または昇格されたオペランドを指します。

1) オペランドをxとし、組み込みビット単位NOT演算の結果をrとします。xの2進数表現の各係数x_iについて、rの2進数表現の対応する係数r_iは、x_i0の場合は1、それ以外の場合は0です。
  • 言い換えれば、結果はオペランドの1の補数です(オペランドと結果は符号なしとみなされます)。
結果rの型はオペランドxの型です。
2-4) オペランドをそれぞれxyとし、組み込みの二項ビット単位論理演算の結果をrとします。xyの2進数表現の各係数ペアx_iy_iについて、rの2進数表現の対応する係数r_iは、
2) x_iy_iの両方が1の場合1、それ以外の場合0
3) x_iy_iの少なくとも一方が1の場合1、それ以外の場合0
4) x_iy_iのいずれか一方(両方ではない)が1の場合1、それ以外の場合0
結果rの型はオペランドxyの型です。

[編集] オーバーロード

ユーザー定義演算子のオーバーロード解決において、昇格された整数型LRのすべてのペアについて、以下の関数シグネチャがオーバーロード解決に参加します。

R operator~(R)
LR operator&(L, R)
LR operator^(L, R)
LR operator|(L, R)

ここで、LRLRに対する通常の算術変換の結果です。

#include <bitset>
#include <cstdint>
#include <iomanip>
#include <iostream>
 
int main()
{
    std::uint16_t mask = 0x00f0;
    std::uint32_t x0 = 0x12345678;
    std::uint32_t x1 = x0 | mask;
    std::uint32_t x2 = x0 & ~mask;
    std::uint32_t x3 = x0 & mask;
    std::uint32_t x4 = x0 ^ mask;
    std::uint32_t x5 = ~x0;
    using bin16 = std::bitset<16>;
    using bin32 = std::bitset<32>;
    std::cout << std::hex << std::showbase
              << "Mask: " << mask << std::setw(49) << bin16(mask) << "\n"
                 "Value: " << x0 << std::setw(42) << bin32(x0) << "\n"
                 "Setting bits: " << x1 << std::setw(35) << bin32(x1) << "\n"
                 "Clearing bits: " << x2 << std::setw(34) << bin32(x2) << "\n"
                 "Selecting bits: " << x3 << std::setw(39) << bin32(x3) << "\n"
                 "XOR-ing bits: " << x4 << std::setw(35) << bin32(x4) << "\n"
                 "Inverting bits: " << x5 << std::setw(33) << bin32(x5) << '\n';
}

出力

Mask: 0xf0                                 0000000011110000
Value: 0x12345678          00010010001101000101011001111000
Setting bits: 0x123456f8   00010010001101000101011011111000
Clearing bits: 0x12345608  00010010001101000101011000001000
Selecting bits: 0x70       00000000000000000000000001110000
XOR-ing bits: 0x12345688   00010010001101000101011010001000
Inverting bits: 0xedcba987 11101101110010111010100110000111

[編集] ビット単位シフト演算子

ビット単位シフト演算子の式は以下の形式をとります。

lhs << rhs (1)
lhs >> rhs (2)
1) ビット単位左シフト。
2) ビット単位右シフト。

ビット単位シフト演算子は、ビット単位論理演算子よりも高い優先順位を持ちますが、加算および乗算演算子よりも低い優先順位を持ちます。これらの演算子は左から右へ結合します。

a >> b * c;  // equivalent to a >> (b * c),  NOT (a >> b) * c
d << e & f;  // equivalent to (d << e) & f,  NOT d << (e & f)
 
g << h >> i; // equivalent to (g << h) >> i, NOT g << (h >> i)

[編集] 組み込みビット単位シフト演算子

組み込みビット単位シフト演算子の場合、両方のオペランドは整数型またはスコープなし列挙型のprvalueでなければなりません。両方のオペランドに対して整数昇格が実行されます。

このセクションの残りの説明では、「オペランド」、ablhsrhsは変換または昇格されたオペランドを指します。

もしrhsの値が負であるか、lhsのビット数以上である場合、動作は未定義です。

符号なしaの場合、a << bの値はa * 2bを戻り値の型のビット数Nを法として減算した値です(つまり、ビット単位左シフトが実行され、目的の型からシフトアウトされたビットは破棄されます)。

符号付きかつ非負のaの場合、もしa * 2bが戻り値の型の符号なし版で表現可能であれば、その値は符号付きに変換され、a << bの値となります(これにより、INT_MIN1 << 31として作成することが合法になります)。それ以外の場合、動作は未定義です。

負のaの場合、a << bの動作は未定義です。

符号なしaおよび符号付きかつ非負のaの場合、a >> bの値はa/2bの整数部分です。

負のaの場合、a >> bの値は実装定義です(ほとんどの実装では、これは算術右シフトを実行し、結果は負のままになります)。

(C++20まで)

a << bの値は、a * 2bを戻り値の型のビット数Nを法として合同な一意の値です(つまり、ビット単位左シフトが実行され、目的の型からシフトアウトされたビットは破棄されます)。

a >> bの値はa/2bであり、負の無限大に向かって丸められます(言い換えれば、符号付きaに対する右シフトは算術右シフトです)。

(C++20以降)

結果の型はlhsの型です。

[編集] オーバーロード

ユーザー定義演算子のオーバーロード解決において、昇格された整数型LRのすべてのペアについて、以下の関数シグネチャがオーバーロード解決に参加します。

L operator<<(L, R)
L operator>>(L, R)
#include <iostream>
 
enum { ONE = 1, TWO = 2 };
 
int main()
{
    std::cout << std::hex << std::showbase;
    char c = 0x10;
    unsigned long long ull = 0x123;
    std::cout << "0x123 << 1 = " << (ull << 1) << "\n"
                 "0x123 << 63 = " << (ull << 63) << "\n" // overflow in unsigned
                 "0x10 << 10 = " << (c << 10) << '\n';   // char is promoted to int
    long long ll = -1000;
    std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n';
}

出力

0x123 << 1 = 0x246
0x123 << 63 = 0x8000000000000000
0x10 << 10 = 0x4000
-1000 >> 1 = -500

[編集] 標準ライブラリ

算術演算子は、多くの標準ライブラリ型でオーバーロードされています。

[編集] 単項算術演算子

単項+および単項-を実装
(std::chrono::duration<Rep,Period>のpublicメンバ関数) [編集]
複素数に単項演算子を適用する
(関数テンプレート) [編集]
valarrayの各要素に単項算術演算子を適用する
(std::valarray<T>のpublicメンバ関数) [編集]

[編集] 加算演算子

タイムポイントを含む加算および減算演算を実行
(関数テンプレート) [編集]
期間を引数とする算術演算を実装
(関数テンプレート) [編集]
year_month_dayと年数または月数を加算または減算
(関数) [編集]
2つの文字列、文字列と char、または文字列と string_view を連結する
(function template) [編集]
イテレータを進めるまたは減らす
(std::reverse_iterator<Iter>のpublicメンバ関数)
イテレータを進めるまたは減らす
(std::move_iterator<Iter>のpublicメンバ関数)
2つの複素数値、または複素数とスカラ値の複素数演算を実行する
(関数テンプレート) [編集]
2つのvalarray、またはvalarrayと値の各要素に二項演算子を適用する
(function template) [編集]

[編集] 乗算演算子

期間を引数とする算術演算を実装
(関数テンプレート) [編集]
2つの複素数値、または複素数とスカラ値の複素数演算を実行する
(関数テンプレート) [編集]
2つのvalarray、またはvalarrayと値の各要素に二項演算子を適用する
(function template) [編集]

[編集] ビット単位論理演算子

ビット単位のAND、OR、XOR、NOTを実行する
(std::bitset<N>のpublicメンバ関数) [編集]
ビットセットに対するビット単位の論理演算を実行する
(function template) [編集]
valarrayの各要素に単項算術演算子を適用する
(std::valarray<T>のpublicメンバ関数)
2つのvalarray、またはvalarrayと値の各要素に二項演算子を適用する
(関数テンプレート)

[編集] ビット単位シフト演算子

2つのvalarray、またはvalarrayと値の各要素に二項演算子を適用する
(関数テンプレート)
ビット単位の左シフトと右シフトを実行する
(std::bitset<N>のpublicメンバ関数)

[編集] ストリーム挿入/抽出演算子

標準ライブラリ全体で、ビット単位シフト演算子はI/Oストリーム(std::ios_base&またはそこから派生したクラスのいずれか)を左オペランドと戻り値の型の両方として持つように一般的にオーバーロードされています。このような演算子はストリーム挿入およびストリーム抽出演算子として知られています。

書式付きデータを抽出する
(std::basic_istream<CharT,Traits>のpublicメンバ関数) [編集]
文字と文字配列を抽出する
(function template) [編集]
書式付きデータを挿入する
(std::basic_ostream<CharT,Traits>のpublicメンバ関数) [編集]
文字データを挿入する、または右辺値ストリームに挿入する
(function template) [編集]
複素数をシリアライズ・デシリアライズする
(関数テンプレート) [編集]
ビットセットのストリーム入出力を実行する
(function template) [編集]
文字列に対するストリーム入出力を実行する
(function template) [編集]
疑似乱数エンジンのストリーム入出力を実行
(関数テンプレート) [編集]
疑似乱数分布のストリーム入出力を実行
(関数テンプレート) [編集]

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 614 C++98 整数除算の代数商は
実装定義の方向に丸められていた
整数の代数商は
ゼロに向かって切り捨てられる
(小数部分は破棄される)
CWG 1450 C++98 a / bの結果は、結果の型で表現できない場合、未指定であった
結果の型で表現できない場合
この場合、a / b
a % bの両方の動作は未定義である
CWG 1457 C++98 正の符号付き値の最左の1ビットを符号ビットにシフトする動作は未定義であった
正の符号付き値の最左の1ビットを
符号ビットにシフトする動作は定義された
CWG 1504 C++98 配列要素の基底クラスサブオブジェクトへのポインタは、ポインタ演算で使用できなかった
配列要素の基底クラスサブオブジェクトへのポインタも
この場合の動作は
未定義となる
ポインタ演算で使用できるようになった C++98 CWG 1515
unsignedと宣言された符号なし整数のみが算術法則modulo 2nに従うべきであった
すべての符号なし整数に適用される
CWG 1642 C++98 算術演算子はオペランドがlvalueであることを許可していた 一部のオペランドはrvalueでなければならない
CWG 1865 C++98 CWG issue 1504の解決により、配列要素へのポインタを含むポインタ演算の動作は未定義になった
指している型と配列要素の型が
非トップレベルで異なるcv修飾を持っている場合
ポインタ演算の動作は未定義になった
符号ビットにシフトする動作は定義された
CWG 1971 C++98 ~の曖昧さを解決する規則が~X(0)のようなケースに適用されるか不明であった
~の曖昧さを解決する規則が
このようなケースにも適用される
CWG 2419 C++98 非配列オブジェクトへのポインタは、&で取得された場合にのみ、サイズ1の配列の最初の要素へのポインタとしてポインタ演算で扱われた
非配列オブジェクトへのポインタは、
&で取得された場合にのみ、サイズ1の配列の最初の要素への
ポインタとしてポインタ演算で扱われた
すべての非配列オブジェクトへのポインタに適用される
CWG 2626 C++98 組み込みoperator~の結果は、「1の補数」としか定義されていなかった
結果は、「1の補数」としか定義されていなかった
結果は2進数表現の観点から表現される
結果は2進数表現の観点から表現される
CWG 2724 C++20 算術右シフトの丸め方向が不明確であった 明確化された
CWG 2853 C++98 オブジェクトの終端を超えるポインタは、整数との加算または減算ができなかった
オブジェクトの終端を超えるポインタも
できる

[編集] 関連項目

演算子の優先順位

演算子のオーバーロード

共通の演算子
代入 インクリメント
デクリメント
算術 論理 比較 メンバ
アクセス
その他

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[...]
*a
&a
a->b
a.b
a->*b
a.*b

関数呼び出し

a(...)
コンマ

a, b
conditional

a ? b : c
特殊な演算子

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ドキュメント - 算術演算子
English 日本語 中文(简体) 中文(繁體)