Namespaces
Variants

operator overloading

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

ユーザー定義型のオペランドに対するC++演算子をカスタマイズします。

目次

構文

Operator functions are functions with special function names:

operator op (1)
operator new
operator new []
(2)
operator delete
operator delete []
(3)
operator co_await (4) (C++20以降)
op - 以下のいずれかの演算子: + - * / % ^ & | ~ ! = < > + = - = * = / = % = ^ = & = | = << >> >>= <<= == ! = <= >= <=> (C++20以降) && || ++ -- , - > * - > ( ) [ ]
1) オーバーロードされた句読点演算子。
2) 割り当て関数 allocation function .
3) 解放関数 deallocation function .
4) コルーチン内で使用するためのオーバーロードされた co_await 演算子。 co_await で使用されます。

句読点以外の演算子の動作はそれぞれの専用ページで説明されています。特に明記されていない限り、このページの残りの説明はこれらの関数には適用されません。

説明

演算子が 内に現れ、そのオペランドの少なくとも1つが クラス型 または 列挙型 を持つ場合、 オーバーロード解決 が使用され、以下のシグネチャに一致するすべての関数の中から呼び出すユーザー定義関数が決定されます:

メンバ関数として 非メンバ関数として
@a (a).operator@ ( ) operator@ (a) ! std:: cin std:: cin . operator ! ( ) を呼び出す
a@b (a).operator@ (b) operator@ (a, b) std:: cout << 42 std:: cout . operator << ( 42 ) を呼び出す
a=b (a).operator= (b) 非メンバでは定義不可 std:: string s ; があるとき、 s = "abc" ; s. operator = ( "abc" ) を呼び出す
a(b...) (a).operator()(b...) 非メンバでは定義不可 std:: random_device r ; があるとき、 auto n = r ( ) ; r. operator ( ) ( ) を呼び出す
a[b...] (a).operator[](b...) 非メンバでは定義不可 std:: map < int , int > m ; があるとき、 m [ 1 ] = 2 ; m. operator [ ] ( 1 ) を呼び出す
a-> (a).operator->( ) 非メンバでは定義不可 std:: unique_ptr < S > p ; があるとき、 p - > bar ( ) p. operator - > ( ) を呼び出す
a@ (a).operator@ (0) operator@ (a, 0) std:: vector < int > :: iterator i ; があるとき、 i ++ i. operator ++ ( 0 ) を呼び出す

この表において、 @ は全ての一致する演算子を表すプレースホルダです:@aでは全ての前置演算子、a@では->以外の全ての後置演算子、a@bでは=以外の全ての中置演算子。

さらに、比較演算子 == ! = < > <= >= <=> について、オーバーロード解決は 書き換え候補 である operator == または operator <=> も考慮します。

(C++20以降)

オーバーロードされた演算子(ただし組み込み演算子は除く)は、関数表記を使用して呼び出すことができます:

std::string str = "Hello, ";
str.operator+=("world");                      // str += "world"; と同じ
operator<<(operator<<(std::cout, str), '\n'); // std::cout << str << '\n'; と同じ
                                              // (C++17以降) シーケンス処理を除く

静的オーバーロード演算子

メンバ関数として定義されたオーバーロード演算子は static として宣言できます。ただし、これは operator ( ) および operator [ ] のみで許可されます。

このような演算子は関数表記を使用して呼び出すことができます。ただし、これらの演算子が式内に現れる場合、依然としてクラス型のオブジェクトが必要です。

struct SwapThem
{
    template<typename T>
    static void operator()(T& lhs, T& rhs) 
    {
        std::ranges::swap(lhs, rhs);
    }
    template<typename T>
    static void operator[](T& lhs, T& rhs)
    {
        std::ranges::swap(lhs, rhs);
    } 
};
inline constexpr SwapThem swap_them{};
void foo()
{
    int a = 1, b = 2;
    swap_them(a, b); // OK
    swap_them[a, b]; // OK
    SwapThem{}(a, b); // OK
    SwapThem{}[a, b]; // OK
    SwapThem::operator()(a, b); // OK
    SwapThem::operator[](a, b); // OK
    SwapThem(a, b); // error, invalid construction
    SwapThem[a, b]; // error
}
(C++23以降)

制限事項

  • 演算子関数は、少なくとも1つの関数パラメータまたは暗黙のオブジェクトパラメータを持たなければならず、その型はクラス、クラスへの参照、列挙型、または列挙型への参照でなければなりません。
  • 演算子 :: (スコープ解決)、 . (メンバアクセス)、 .* (メンバポインタ経由のメンバアクセス)、および ?: (三項条件演算子)はオーバーロードできません。
  • ** <> &| のような新しい演算子を作成することはできません。
  • 演算子の優先順位、結合規則、またはオペランドの数を変更することはできません。
  • 演算子 -> のオーバーロードは、生ポインタを返すか、または演算子 -> がさらにオーバーロードされているオブジェクト(参照または値による)を返さなければなりません。
  • 演算子 && || のオーバーロードでは、短絡評価が失われます。
  • && || 、および , は、オーバーロードされると特殊な シーケンシング特性 を失い、関数呼び出し記法なしで使用された場合でも通常の関数呼び出しと同様に振る舞います。
(C++17まで)

標準実装

上記の制限に加えて、言語はオーバーロードされた演算子が何を行うか、または戻り値の型(オーバーロード解決には参加しません)について他の制約を課しませんが、一般的に、オーバーロードされた演算子は組み込み演算子と可能な限り類似した動作をすることが期待されます: operator + は引数を乗算するのではなく加算することが期待され、 operator = は代入することが期待されます、など。関連する演算子は同様に動作することが期待されます( operator + operator + = は同じ加算的な操作を行います)。戻り値の型は、演算子が使用されると期待される式によって制限されます:例えば、代入演算子は参照によって返すため、 a = b = c = d と書くことが可能になります、なぜなら組み込み演算子がそれを許可しているからです。

一般的にオーバーロードされる演算子には以下の典型的な正規形式があります: [1]

代入演算子

代入演算子 operator = には特別な特性があります:詳細は copy assignment および move assignment を参照してください。

正規のコピー代入演算子は、 自己代入に対して安全であること が求められ、左辺値を参照で返す必要があります:

// コピー代入
T& operator=(const T& other)
{
    // 自己代入の防止
    if (this == &other)
        return *this;
    // *thisがヒープ割り当てバッファmArrayなどの再利用可能なリソースを管理していると仮定
    if (size != other.size)           // *this内のリソースは再利用できない
    {
        temp = new int[other.size];   // リソースを割り当て、例外が発生した場合は何もしない
        delete[] mArray;              // *this内のリソースを解放
        mArray = temp;
        size = other.size;
    }
    std::copy(other.mArray, other.mArray + other.size, mArray);
    return *this;
}

正規のムーブ代入は、ムーブ元のオブジェクトを 有効な状態 にすること(つまり、クラスの不変条件が維持された状態)、自己代入に対しては 何もしない か少なくとも有効な状態を維持すること、非const参照で左辺値を返すこと、そしてnoexceptであることが期待されます:

// move assignment
T& operator=(T&& other) noexcept
{
    // Guard self assignment
    if (this == &other)
        return *this; // delete[]/size=0 would also be ok
    delete[] mArray;                               // release resource in *this
    mArray = std::exchange(other.mArray, nullptr); // leave other in valid state
    size = std::exchange(other.size, 0);
    return *this;
}
(C++11以降)

コピー代入がリソースの再利用の恩恵を受けない状況(ヒープ割り当て配列を管理しておらず、かつ(推移的に)管理するメンバー、例えば std::vector std::string のようなメンバーを持たない場合)では、一般的で便利な省略記法が存在します:コピー・アンド・スワップ代入演算子です。これはパラメータを値で受け取り(したがって引数の値カテゴリに応じてコピー代入とムーブ代入の両方として機能)、パラメータとスワップし、デストラクタに後処理を任せます。

// コピー代入(コピー・アンド・スワップ慣用句)
T& T::operator=(T other) noexcept // コピーまたはムーブコンストラクタを呼び出してotherを構築
{
    std::swap(size, other.size); // *thisとotherの間でリソースを交換
    std::swap(mArray, other.mArray);
    return *this;
} // otherのデストラクタが呼び出され、以前*thisが管理していたリソースを解放

このフォームは自動的に strong exception guarantee を提供しますが、リソースの再利用を禁止します。

ストリーム抽出と挿入

operator>> および operator<< のオーバーロードで、左辺引数として std:: istream & または std:: ostream & を取るものは、挿入演算子および抽出演算子として知られています。これらはユーザー定義型を右辺引数として取るため( a @ b b )、非メンバ関数として実装されなければなりません。

std::ostream& operator<<(std::ostream& os, const T& obj)
{
    // オブジェクトをストリームに書き込む
    return os;
}
std::istream& operator>>(std::istream& is, T& obj)
{
    // ストリームからオブジェクトを読み込む
    if (/* T の構築に失敗した場合 */)
        is.setstate(std::ios::failbit);
    return is;
}

これらの演算子は、時として friend関数 として実装されます。

関数呼び出し演算子

ユーザー定義クラスが関数呼び出し演算子 operator ( ) をオーバーロードすると、それは FunctionObject 型となります。

この型のオブジェクトは関数呼び出し式で使用できます:

// この型のオブジェクトは、1変数の線形関数 a * x + b を表します。
struct Linear
{
    double a, b;
    double operator()(double x) const
    {
        return a * x + b;
    }
};
int main()
{
    Linear f{2, 1};  // 関数 2x + 1 を表します。
    Linear g{-1, 0}; // 関数 -x を表します。
    // f と g は関数のように使用できるオブジェクトです。
    double f_0 = f(0);
    double f_1 = f(1);
    double g_0 = g(0);
}

多くの標準ライブラリ アルゴリズム は動作をカスタマイズするために FunctionObject s を受け入れます。 operator ( ) の特に注目すべき標準的な形式はありませんが、使用法を説明するために:

#include <algorithm>
#include <iostream>
#include <vector>
struct Sum
{
    int sum = 0;
    void operator()(int n) { sum += n; }
};
int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5};
    Sum s = std::for_each(v.begin(), v.end(), Sum());
    std::cout << "The sum is " << s.sum << '\n';
}

出力:

The sum is 15

インクリメントとデクリメント

後置インクリメント演算子またはデクリメント演算子が式内に現れる場合、対応するユーザー定義関数( operator ++ または operator -- )が整数引数 0 を伴って呼び出されます。通常、これは T operator ++ ( int ) または T operator -- ( int ) として宣言され、引数は無視されます。後置インクリメント演算子とデクリメント演算子は通常、前置バージョンを用いて実装されます:

struct X
{
    // 前置インクリメント
    X& operator++()
    {
        // 実際のインクリメントはここで行われる
        return *this; // 新しい値を参照で返す
    }
    // 後置インクリメント
    X operator++(int)
    {
        X old = *this; // 古い値をコピー
        operator++();  // 前置インクリメント
        return old;    // 古い値を返す
    }
    // 前置デクリメント
    X& operator--()
    {
        // 実際のデクリメントはここで行われる
        return *this; // 新しい値を参照で返す
    }
    // 後置デクリメント
    X operator--(int)
    {
        X old = *this; // 古い値をコピー
        operator--();  // 前置デクリメント
        return old;    // 古い値を返す
    }
};

前置インクリメント演算子と前置デクリメント演算子の標準的な実装は参照を返しますが、あらゆる演算子オーバーロードと同様に、戻り値の型はユーザー定義です。例えば、 std::atomic に対するこれらの演算子のオーバーロードは値を返します。

二項算術演算子

二項演算子は通常、対称性を維持するために非メンバとして実装されます(例えば、複素数と整数を加算する場合、 operator + が複素数型のメンバ関数である場合、 complex + integer のみがコンパイルされ、 integer + complex はコンパイルされません)。すべての二項算術演算子に対して対応する複合代入演算子が存在するため、二項演算子の標準的な形式はそれらの複合代入演算子を用いて実装されます:

class X
{
public:
    X& operator+=(const X& rhs) // 複合代入(メンバーである必要はないが、
    {                           // プライベートメンバーを変更するためによく使用される)
        /* rhsを*thisに加算する処理がここで行われる */
        return *this; // 参照で結果を返す
    }
    // クラス内で定義されたフレンド関数はインラインであり、非ADLルックアップから隠蔽される
    friend X operator+(X lhs,        // lhsを値渡しすることでa+b+cのような連鎖演算を最適化
                       const X& rhs) // それ以外の場合、両パラメータはconst参照となる
    {
        lhs += rhs; // 複合代入を再利用
        return lhs; // 値で結果を返す(ムーブコンストラクタを使用)
    }
};

比較演算子

std::sort std::set のような標準ライブラリのアルゴリズムやコンテナは、ユーザー定義型に対してデフォルトで operator < が定義されていることを期待し、それが狭義の弱順序(したがって Compare 要件を満たす)を実装していることを期待します。構造体に対して狭義の弱順序を実装する慣用的な方法は、 std::tie によって提供される辞書式比較を使用することです:

struct Record
{
    std::string name;
    unsigned int floor;
    double weight;
    friend bool operator<(const Record& l, const Record& r)
    {
        return std::tie(l.name, l.floor, l.weight)
             < std::tie(r.name, r.floor, r.weight); // 同じ順序を維持
    }
};

一般的に、 operator < が提供されると、他の関係演算子は operator < を用いて実装されます。

inline bool operator< (const X& lhs, const X& rhs) { /* 実際の比較を実行 */ }
inline bool operator> (const X& lhs, const X& rhs) { return rhs < lhs; }
inline bool operator<=(const X& lhs, const X& rhs) { return !(lhs > rhs); }
inline bool operator>=(const X& lhs, const X& rhs) { return !(lhs < rhs); }

同様に、不等号演算子は通常、 operator == を用いて実装されます:

inline bool operator==(const X& lhs, const X& rhs) { /* 実際の比較を実行 */ }
inline bool operator!=(const X& lhs, const X& rhs) { return !(lhs == rhs); }

三方比較(例えば std::memcmp std::string::compare )が提供されている場合、6つの二項比較演算子はすべてそれを通して表現できます:

inline bool operator==(const X& lhs, const X& rhs) { return cmp(lhs,rhs) == 0; }
inline bool operator!=(const X& lhs, const X& rhs) { return cmp(lhs,rhs) != 0; }
inline bool operator< (const X& lhs, const X& rhs) { return cmp(lhs,rhs) <  0; }
inline bool operator> (const X& lhs, const X& rhs) { return cmp(lhs,rhs) >  0; }
inline bool operator<=(const X& lhs, const X& rhs) { return cmp(lhs,rhs) <= 0; }
inline bool operator>=(const X& lhs, const X& rhs) { return cmp(lhs,rhs) >= 0; }
**注記**: 提供されたコードはC++の比較演算子オーバーロードの実装であり、HTMLタグ内のコードブロックとして保護されています。指示に従い、コード部分は翻訳せず、HTML構造とフォーマットを完全に保持しています。

配列添字演算子

配列のような読み書き両方のアクセスを提供するユーザー定義クラスは、通常、 operator [ ] に対してconstと非constの2つのオーバーロードを定義します:

struct T
{
          value_t& operator[](std::size_t idx)       { return mVector[idx]; }
    const value_t& operator[](std::size_t idx) const { return mVector[idx]; }
};

あるいは、 明示的なオブジェクトパラメータ を使用して単一のメンバー関数テンプレートとして表現することもできます:

struct T
{
    decltype(auto) operator[](this auto& self, std::size_t idx) 
    { 
        return self.mVector[idx]; 
    }
};
(C++23以降)

値の型がスカラー型であることがわかっている場合、constバリアントは値で返すべきです。

コンテナの要素への直接アクセスが望ましくない、または不可能な場合、あるいは左辺値 c [ i ] = v ; と右辺値 v = c [ i ] ; の使用を区別する必要がある場合、 operator [ ] はプロキシを返すことがあります。例として std::bitset::operator[] を参照してください。

operator [ ] は単一の添字しか受け取れません。多次元配列アクセスのセマンティクスを提供するためには、例えば3次元配列アクセス a [ i ] [ j ] [ k ] = x ; を実装する場合、 operator [ ] は2次元平面への参照を返し、その平面が独自の operator [ ] を持って1次元行への参照を返し、さらにその行が operator [ ] を持って要素への参照を返す必要があります。この複雑さを回避するため、一部のライブラリでは代わりに operator ( ) をオーバーロードし、3次元アクセス式をFortran風の構文 a ( i, j, k ) = x ; で表現することを選択しています。

(C++23まで)

operator [ ] は任意の数の添字を受け取ることができます。例えば、3次元配列クラスの operator [ ] T & operator [ ] ( std:: size_t x, std:: size_t y, std:: size_t z ) ; として宣言されている場合、要素に直接アクセスできます。

#include <array>
#include <cassert>
#include <iostream>
template<typename T, std::size_t Z, std::size_t Y, std::size_t X>
struct Array3d
{
    std::array<T, X * Y * Z> m{};
    constexpr T& operator[](std::size_t z, std::size_t y, std::size_t x) // C++23
    {
        assert(x < X and y < Y and z < Z);
        return m[z * Y * X + y * X + x];
    }
};
int main()
{
    Array3d<int, 4, 3, 2> v;
    v[3, 2, 1] = 42;
    std::cout << "v[3, 2, 1] = " << v[3, 2, 1] << '\n';
}

出力:

v[3, 2, 1] = 42
(C++23以降)

ビット演算演算子

BitmaskType の要件を実装するユーザー定義クラスおよび列挙型は、ビット単位演算子 operator & operator | operator ^ operator~ operator & = operator | = 、および operator ^ = をオーバーロードする必要があり、シフト演算子 operator << operator >> operator >>= 、および operator <<= をオプションでオーバーロードすることができます。標準的な実装は通常、前述の二項算術演算子のパターンに従います。

論理否定演算子

operator operator ! は、ブーリアンコンテキストで使用されることを意図したユーザー定義クラスによって一般的にオーバーロードされます。このようなクラスはまた、ブーリアン型へのユーザー定義変換関数を提供し(標準ライブラリの例については std::basic_ios を参照)、 operator ! の期待される動作は operator bool の反対の値を返すことです。

(C++11以前)

組み込みのoperator ! 文脈に応じた bool への変換 を実行するため、ブーリアンコンテキストで使用されることを意図したユーザー定義クラスは operator bool のみを提供すればよく、 operator ! をオーバーロードする必要はありません。

(C++11以降)

稀にオーバーロードされる演算子

以下の演算子は稀にしかオーバーロードされません:

  • アドレス取得演算子、 operator & 。単項&が不完全型の左辺値に適用され、完全型がオーバーロードされた operator & を宣言している場合、演算子が組み込みの意味を持つか演算子関数が呼び出されるかは未規定です。この演算子はオーバーロード可能なため、ジェネリックライブラリではユーザー定義型のオブジェクトのアドレスを取得するために std::addressof を使用します。標準的なオーバーロード例として最もよく知られているのはMicrosoftのクラス CComPtrBase です。この演算子のEDSLでの使用例は boost.spirit で見つけることができます。
  • 論理演算子、 operator && および operator || 。組み込みバージョンとは異なり、オーバーロード版では短絡評価を実装できません。 また組み込みバージョンとは異なり、左側のオペランドを右側のオペランドより前に順序付けしません。 (C++17まで) 標準ライブラリでは、これらの演算子は std::valarray に対してのみオーバーロードされています。
  • コンマ演算子、 operator, 組み込みバージョンとは異なり、オーバーロード版では左側のオペランドを右側のオペランドより前に順序付けしません。 (C++17まで) この演算子はオーバーロード可能なため、ジェネリックライブラリではユーザー定義型の式の実行順序を制御するために a, void ( ) , b のような式を a, b の代わりに使用します。Boostライブラリでは operator, boost.assign boost.spirit およびその他のライブラリで使用されています。データベースアクセスライブラリの SOCI operator, をオーバーロードしています。
  • メンバポインタを通じたメンバアクセス演算子 operator - > * 。この演算子をオーバーロードすることに特定の欠点はありませんが、実際にはほとんど使用されません。これは スマートポインタインターフェース の一部となり得ることが提案されており、実際に boost.phoenix のアクターでその目的で使用されています。 cpp.react のようなEDSLではより一般的です。

注記

機能テスト マクロ 標準 機能
__cpp_static_call_operator 202207L (C++23) static operator ( )
__cpp_multidimensional_subscript 202211L (C++23) static operator [ ]

キーワード

operator

#include <iostream>
class Fraction
{
    // or C++17's std::gcd
    constexpr int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
    int n, d;
public:
    constexpr Fraction(int n, int d = 1) : n(n / gcd(n, d)), d(d / gcd(n, d)) {}
    constexpr int num() const { return n; }
    constexpr int den() const { return d; }
    constexpr Fraction& operator*=(const Fraction& rhs)
    {
        int new_n = n * rhs.n / gcd(n * rhs.n, d * rhs.d);
        d = d * rhs.d / gcd(n * rhs.n, d * rhs.d);
        n = new_n;
        return *this;
    }
};
std::ostream& operator<<(std::ostream& out, const Fraction& f)
{
   return out << f.num() << '/' << f.den();
}
constexpr bool operator==(const Fraction& lhs, const Fraction& rhs)
{
    return lhs.num() == rhs.num() && lhs.den() == rhs.den();
}
constexpr bool operator!=(const Fraction& lhs, const Fraction& rhs)
{
    return !(lhs == rhs);
}
constexpr Fraction operator*(Fraction lhs, const Fraction& rhs)
{
    return lhs *= rhs;
}
int main()
{
    constexpr Fraction f1{3, 8}, f2{1, 2}, f3{10, 2};
    std::cout << f1 << " * " << f2 << " = " << f1 * f2 << '\n'
              << f2 << " * " << f3 << " = " << f2 * f3 << '\n'
              <<  2 << " * " << f1 << " = " <<  2 * f1 << '\n';
    static_assert(f3 == f2 * 10);
}

出力:

3/8 * 1/2 = 3/16
1/2 * 5/1 = 5/2
2 * 3/8 = 3/4

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR Applied to Behavior as published Correct behavior
CWG 1481 C++98 非メンバー前置インクリメント演算子はクラス型、列挙型、またはそれらの型への参照型のパラメータのみを持つことができた 型の要件なし
CWG 2931 C++23 明示的オブジェクトメンバー演算子関数はクラス型、列挙型、またはそれらの型への参照型のパラメータのみを持つことができた 禁止

関連項目

HTMLタグと属性、および` `タグ内のC++コードは翻訳せず、元のフォーマットを保持しました。「comma」のみを「カンマ」に翻訳しています。
一般的な演算子
代入 インクリメント
デクリメント
算術 論理 比較 メンバー
アクセス
その他

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
条件演算子

a ? b : c
特殊演算子

static_cast 関連する型間で変換を行う
dynamic_cast 継承階層内で変換を行う
const_cast cv 修飾子を追加または削除する
reinterpret_cast 関連のない型間で変換を行う
Cスタイルキャスト static_cast const_cast reinterpret_cast の組み合わせで型変換を行う
new 動的ストレージ期間を持つオブジェクトを作成する
delete new式で作成されたオブジェクトを破棄し、確保されたメモリ領域を解放する
sizeof 型のサイズを問い合わせる
sizeof... パック のサイズを問い合わせる (C++11以降)
typeid 型の型情報を問い合わせる
noexcept 式が例外を投げる可能性があるかチェックする (C++11以降)
alignof 型のアライメント要件を問い合わせる (C++11以降)

外部リンク

  1. Operator Overloading on StackOverflow C++ FAQ