namespace std {
template <class U, class PtrT, unsigned int BitsRequested,
size_t Alignment = alignof(U)>
concept tagging-compatible-pointee = // 説明専用
convertible_to<U*, PtrT> &&
pointer_bits_available(Alignment) >= BitsRequested &&
(is_void_v<element-of<PtrT>> ||
is_scalar_v<element-of<PtrT>> ||
is_union_v<element-of<PtrT>> ||
is_pointer_interconvertible_base_of_v<element-of<PtrT>, U>);
}
概要
tagging-compatible-pointeeは、型Uのポインタが、PtrT型のポインタとしてBitsRequestedビットのタグ付けと互換であることを表す説明専用コンセプトである。
pointer_tag_pairのコンストラクタとfrom_overaligned()の制約として使用される。
要件
以下のすべてを満たすこと。
U*がPtrTへ変換可能であることpointer_bits_available(Alignment) >= BitsRequestedであること(アライメントから、要求したビット数を確保できること)- 指す先の型(説明専用の
element-of<PtrT>。pointer_traits<PtrT>::element_type)が次のいずれかであることvoid・スカラ型・共用体であるUのポインタ相互変換可能 (pointer-interconvertible) な基底クラスである。これによって、仮想継承や先頭以外の基底クラスへのポインタなど、アドレス調整をともなうポインタ変換が除外される
例
#include <memory>
struct Base { int a; };
struct Derived : Base {}; // 追加のメンバがないため標準レイアウト
struct WithMember : Base { int b; };
struct Virt : virtual Base { int c; };
int main()
{
Derived d{};
WithMember w{};
Virt v{};
char c = 0;
// OK : Derivedのアライメントは4なので、1ビットのタグを確保できる。
// BaseはDerivedのポインタ相互変換可能な基底クラスであり、
// Derived*からBase*への変換でアドレスは変わらない
std::pointer_tag_pair<Base*, 1> p1{&d, 1u};
// コンパイルエラー! WithMemberは基底クラスと派生クラスの両方にメンバを持ち、
// 標準レイアウトではないため、ポインタ相互変換可能ではない
// std::pointer_tag_pair<Base*, 1> p2{&w, 1u};
// コンパイルエラー! 仮想継承では、ポインタの変換にアドレスの調整をともなうため、
// 下位ビットのタグが保たれる保証がない
// std::pointer_tag_pair<Base*, 1> p3{&v, 1u};
// コンパイルエラー! charのアライメントは1なので、タグ用のビットを確保できない
// std::pointer_tag_pair<char*, 1> p4{&c, 1u};
}
出力
バージョン
言語
- C++29
処理系
- Clang: ??
- GCC: ??
- Visual C++: ??