1

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 を削除しますか?

4

1 に答える 1

5

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

于 2016-12-21T17:00:02.053 に答える