C++14 ドラフト n4140 読み取り
T
列挙型でなければならない
のためにtemplate <class T> struct underlying_type
。
書き方が悪い
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>
いつT
任意の型になることができますか? 私は UB に足を踏み入れ、コンパイラーは私の $HOME を削除しますか?
C++14 ドラフト n4140 読み取り
T
列挙型でなければならない
のためにtemplate <class T> struct underlying_type
。
書き方が悪い
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>
いつT
任意の型になることができますか? 私は UB に足を踏み入れ、コンパイラーは私の $HOME を削除しますか?
UBに足を踏み入れますか[...]
技術的には、はい。しかし、実際には、非列挙型に対してはコンパイルされません。あなたが書くとき:
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>;
^^^^^^^^^^^^^^^^^^^^^^^^^
テンプレートをインスタンス化する前に、そのテンプレート パラメータを評価する必要があります。conditional
これは、関数の本体が始まる前にすべての関数引数を呼び出す必要があることと同じです。列挙されていない型の場合、underlying_type<T>
は不完全です (標準では未定義として指定されていますが、合理的に考えてください) underlying_type_t
。したがって、インスタンス化は失敗します。
その場合、インスタンス化を遅らせる必要があります。
template <class T> struct tag { using type = T; };
typename std::conditional_t<
std::is_enum<T>::value,
std::underlying_type<T>,
tag<foo>>::type;
ここで、conditional
型を選択する代わりに、メタ関数を選択しています! 列挙型であるunderlying_type<T>::type
ためにのみインスタンス化されます。さらに、それをメタ関数に変換するためT
にラップする必要があります。foo
これは一般的なパターンで、Boost.MPL では と呼ばれる特別なもので、次のeval_if
ようになります。
template <bool B, class T, class F>
using eval_if_t = typename std::conditional_t<B, T, F>::type;
conditional_t
と の両方を使用し ていることに注意してください::type
。