Namespaces
Variants

Extending the namespace std

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

目次

std への宣言の追加

std 名前空間、または std 内のネストされた名前空間に宣言や定義を追加することは未定義動作となります。ただし、以下に記載する例外がいくつかあります。

#include <utility>
namespace std
{
    // 名前空間stdに追加された関数定義: 未定義動作
    pair<int, int> operator+(pair<int, int> a, pair<int, int> b)
    {
        return {a.first + b.first, a.second + b.second};
    }
}

テンプレート特殊化の追加

クラステンプレート

名前空間 std に対する標準ライブラリのクラステンプレートの特殊化は、宣言が少なくとも1つの program-defined type に依存しており、かつその特殊化が元のテンプレートに対する全ての要件を満たす場合にのみ許可されます。ただし、そのような特殊化が禁止されている場合を除きます。

// 主要なstd::hashテンプレートの宣言を取得する
// 自ら宣言することは許可されていない
// <typeindex>はそのような宣言を提供することが保証されており、
// <functional>を含めるよりもはるかにコストが低い
#include <typeindex> 
// std::hashを特殊化して、MyTypeをstd::unordered_setおよび
// std::unordered_mapのキーとして使用できるようにする。std名前空間を
// 開くことは未定義動作を誤って導入する可能性があり、クラステンプレートの
// 特殊化には必要ない
template<>
struct std::hash<MyType>
{
    std::size_t operator()(const MyType& t) const { return t.hash(); }
};
  • テンプレート std::complex float double 、および long double 以外の型に対して特殊化することは未規定です。
  • std::numeric_limits の特殊化は、プライマリテンプレートで宣言されたすべてのメンバを static const (until C++11) static constexpr (since C++11) として定義しなければならず、 整数定数式 として使用可能な形でなければなりません。
  • プログラム定義型に対する std::hash の特殊化は、 Hash 要件を満たさなければならない。
  • std::atomic の特殊化は、削除されたコピーコンストラクタ、削除されたコピー代入演算子、およびconstexpr値コンストラクタを持たなければならない。
  • std::istreambuf_iterator の特殊化は、自明なコピーコンストラクタ、constexprデフォルトコンストラクタ、および自明なデストラクタを持たなければならない。
(C++11以降)
(C++17まで)

標準ライブラリのクラスまたはクラステンプレートのメンバークラステンプレートの完全特殊化または部分特殊化を宣言することは未定義動作です。

関数テンプレートとテンプレートのメンバー関数

標準ライブラリの関数テンプレートに対して、以下の条件を満たす場合に限り、名前空間 std へのテンプレート特殊化が許可される:宣言が少なくとも1つの プログラム定義型 に依存しており、その特殊化が元のテンプレートのすべての要件を満たすこと。ただし、そのような特殊化が禁止されている場合は除く。

(C++20まで)

標準ライブラリの関数テンプレートの完全特殊化を宣言することは未定義動作である。

(C++20以降)

標準ライブラリのクラステンプレートのメンバ関数の完全特殊化を宣言することは未定義動作です:

標準ライブラリのクラスまたはクラステンプレートのメンバー関数テンプレートの完全特殊化を宣言することは未定義動作です:

変数テンプレート

標準ライブラリの変数テンプレートの完全または部分特殊化を宣言することは、明示的に許可されている場合を除き、未定義動作です。

(C++20以降)
(C++14以降)

テンプレートの明示的インスタンス化

標準ライブラリで定義された クラス (C++20以降) テンプレートの明示的なインスタンス化は、宣言が少なくとも1つの program-defined type の名前に依存しており、かつそのインスタンス化が元のテンプレートに対する標準ライブラリの要件を満たす場合にのみ許可されます。

その他の制限

名前空間 std inline namespace として宣言することはできません。

アドレス取得制限

C++プログラムが、標準ライブラリ関数または標準ライブラリ関数テンプレートのインスタンス化へのポインタ、参照(フリー関数および静的メンバ関数の場合)、またはメンバへのポインタ(非静的メンバ関数の場合)を明示的または暗黙的に形成しようとする場合、その動作は未規定(場合によっては不適格)となる。ただし、以下で定義される アドレス可能関数 として指定されている場合は除く。

以下のコードはC++17では適切に定義されていたが、C++20以降では未規定の動作を引き起こし、コンパイルに失敗する可能性がある:

#include <cmath>
#include <memory>
int main()
{
    // 単項演算子&による
    auto fptr0 = &static_cast<float(&)(float, float)>(std::betaf);
    // std::addressofによる
    auto fptr1 = std::addressof(static_cast<float(&)(float, float)>(std::betaf));
    // 関数からポインタへの暗黙変換による
    auto fptr2 = static_cast<float(&)(float)>(std::riemann_zetaf);
    // 参照の形成
    auto& fref = static_cast<float(&)(float)>(std::riemann_zetaf);
}

指定されたアドレス可能関数

(C++20以降)

不具合報告

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

DR 適用対象 公開時の動作 正しい動作
LWG 120 C++98 ユーザーが非ユーザー定義型に対する標準ライブラリ
テンプレートの明示的インスタンス化が可能だった
禁止
LWG 232 C++98 ユーザーが標準ライブラリテンプレートの明示的特殊化が可能だった
(宣言が外部リンケージを持つユーザー定義名に依存する場合、
これは非ユーザー定義型を参照可能)
ユーザー定義型のみ
許可
LWG 422 C++98 ユーザーが個々のメンバーやメンバーテンプレートを特殊化可能だった
(標準ライブラリのクラス全体やクラステンプレート全体を特殊化せずに)
この場合の動作は
未定義