namespace std {
template <class T>
struct is_literal_type;
template <class T>
inline constexpr bool is_literal_type_v = is_literal_type<T>::value; // C++17
}
この機能は、C++17から非推奨となり、C++20で削除された。
概要
型T
がリテラル型か調べる。
要件
型remove_all_extents<T>::type
は、完全型か、const
/volatile
修飾された(あるいはされていない)void
でなければならない。
効果
is_literal_type
は、型T
がリテラル型であるならばtrue_type
から派生し、そうでなければfalse_type
から派生する。
リテラル型とは、以下のいずれかの条件を満たす型である:
- スカラ型
- リテラル型への参照
- リテラル型の配列
- 以下の全ての特性を持つクラス型
- トリビアルなデストラクタを持つ
- 全てのコンストラクタが、定数式で初期化できること
- 集成体であること、もしくはコピー/ムーブコンストラクタ以外の
constexpr
コンストラクタやconstexpr
コンストラクタテンプレートを一つ以上持っていること - 全てのメンバ変数および基底クラスがリテラル型であること
void
(C++14から)
リテラル型は、constexpr
関数のパラメータおよび戻り値の型に対する制約として使用されている。
非推奨・削除の詳細
この型特性は、ジェネリックコードにおいて特定の型がconstexpr
に振る舞えるかを判定する機能を持つが、ユーザー定義型の場合には「少なくとも一つ以上のconstexpr
コンストラクタを持つこと」という条件になっていた。しかし、いずれかのコンストラクタがconstexpr
で、それ以外がconstexpr
コンストラクタではなく、それに意味がある場合に、この型特性は使いにくかった。
実際に必要となるのは、特定の型がconstexpr
に振る舞えるかではなく、特定の構築処理で定数初期化ができるかであるため、リテラル型という考え方は廃止すべきである、という結論になった。
例
#include <type_traits>
struct X {
int value;
constexpr X(int value)
: value(value) {}
};
static_assert(std::is_literal_type<int>::value, "int is literal type");
static_assert(std::is_literal_type<void>::value, "void is literal type");
static_assert(std::is_literal_type<X>::value, "X is literal type");
int main() {}
#include <type_traits>
struct X {
int value;
constexpr X(int value)
: value(value) {}
};
static_assert(std::is_literal_type<int>::value, "int is literal type");
static_assert(std::is_literal_type<void>::value, "void is literal type");
static_assert(std::is_literal_type<X>::value, "X is literal type");
int main() {}
出力
バージョン
言語
- C++11
処理系
- Clang: 3.1 ✅
- GCC: 4.6.4 ✅
- Visual C++: 2012 ✅, 2013 ✅, 2015 ✅
- 2012~2013は、C++11の定義に基づく実装となっている。すなわち、テンプレート実引数として
void
を渡すとstd::false_type
からの派生になる。
- 2012~2013は、C++11の定義に基づく実装となっている。すなわち、テンプレート実引数として
備考
Clang 3.0では、上記サンプルにおけるX
型が、リテラル型と見なされない。この問題は、Clang 3.1で修正されている。
参照
- LWG Issue 2015. Incorrect pre-conditions for some type traits
- C++11では要件が「型
T
は完全型であるか、const
/volatile
修飾された(あるいはされていない)void
か、要素数不明の配列型でなければならない。」だったが、これは間違いであるため、C++14で「型remove_all_extents<T>::type
は、完全型か、const
/volatile
修飾された(あるいはされていない)void
でなければならない。」に変更された。
- C++11では要件が「型
- P0006R0 Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17
- P0174R2 Deprecating Vestigial Library Parts in C++17
- P0619R4 Reviewing deprecated facilities of C++17 for C++20
- LWG Issue
is_literal_type_v
should beinline