namespace std {
template <class T>
struct has_unique_object_representations;
template <class T>
inline constexpr bool has_unique_object_representations_v
= std::has_unique_object_representations<T>::value;
}
概要
型T
の任意の2つの値が、同じ値を持つ場合はそのオブジェクト表現(バイト表現)も同じとなるかどうかを調べる。
要件
型T
が、完全型であること。もしくはconst
/volatile
修飾された(あるいはされていない)void
か、要素数不明の配列型であること。
効果
型T
がTriviallyCopyableであり、T
の任意の2つの値が等価(equivalent)であるならバイト表現が等値(equal)となる場合に
true_type
から派生し、そうでなければfalse_type
から派生する。
以下、もう少し詳細な解説。
まず、型T
のオブジェクト表現とは、T
のオブジェクトを型unsigned char[N]
で参照したときのバイト列のことである(N == sizeof(T)
)。
次に、型T
の値表現とは、T
の値を保持するビット列のことである。
そして、T
がTriviallyCopyableであれば、値表現はオブジェクト表現内に含まれる。
この時、T
の値表現とオブジェクト表現がビット単位で正確に一致していればhas_unique_object_representations<T>::value == true
となる。
構造体のパディングはオブジェクト表現に含まれるが、値表現には含まれない。したがって、パディングを持つ構造体は値が同じでもバイト表現が同じとは限らない(結果はfalse
となる)。
スカラー型がこの性質を満たすかは処理系定義となるが、符号なし整数型は一意なオブジェクト表現を持つ。
またC++20以降、符号付整数型は2の補数表現であると規定されるため、C++20以降は(現在でも多くの処理系がそうであるが)符号付も含めた整数型がこの性質を満たすようになる。
また、多くの処理系において IEC 559 (IEEE 754) に準拠する浮動小数点型がこの性質を満たさない。
ビットフィールドも処理系によってバイト表現が異なるため処理系定義となる(主に、Itanium ABIとMSVC ABI間で異なる)。
T
型の二つのオブジェクトが同じ値を持つとは、以下の場合である:
T
型の二つのオブジェクトが同じオブジェクト表現を持っており、かつT
が配列なら、2つの配列のそれぞれの要素が同じ値を持つT
が共用体でないクラス型なら、対応する非静的メンバ変数が同じ値を持つT
が共用体なら、2つの共用体が同じアクティブメンバを持ち、対応するメンバが同じ値を持つ- それ以外の場合、その2つのオブジェクトの
operator==
による比較がtrue
となる
備考
このメタ関数は、簡易にハッシュを求めることを将来サポートする前準備として、ある型のバイト列をそのままその型のハッシュとして利用できるかを判定するために追加された。
おそらく、実装はコンパイラーマジックによって行われ、ユーザーコードで実装することは出来ないと思われる。
例
#include <type_traits>
#include <iostream>
struct unique_object_representations {
int a;
int b;
};
struct not_unique_object_representations {
char a;
// 後続メンバbが配置されるメモリアドレスをint型にとって自然なアライメントとするため、
// 多くの処理系ではここにパディングを挿入する。例:sizeof(int)==4環境では3バイト。
// pragmaやコンパイルオプションなど処理系独自の手段でパディング量は調整できることが多い。
int b;
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::has_unique_object_representations<int>::value << std::endl;
std::cout << std::has_unique_object_representations<unsigned int>::value << std::endl;
// IEC 559(IEEE 754)準拠の浮動小数点型では、異なるバイト列であっても等価となるケースが存在する。
// 正のゼロ(+0.0)と負のゼロ(-0.0)は等価と評価されるが、それぞれの値を表すバイト列は異なっている。
std::cout << std::has_unique_object_representations<float>::value << std::endl;
std::cout << std::has_unique_object_representations<double>::value << std::endl;
std::cout << std::has_unique_object_representations<unique_object_representations>::value << std::endl;
std::cout << std::has_unique_object_representations<not_unique_object_representations>::value << std::endl;
}
出力例
true
true
false
false
true
false
バージョン
言語
- C++17
処理系
- Clang: 6.0 ✅
- GCC: 7.1 ✅
- Visual C++: 2017 Update 3 ✅