web-dev-qa-db-ja.com

タイプTがパラメーターパックTsの中にあることをどのように確認できますか?

TTs...のいずれかである場合にtrueを返す関数を記述したい

template<class T, class... Ts>
bool is_one_of<T, Ts...>();

たとえば、is_one_of<int, double, int, float>trueを返し、is_one_of<int, double, std::string, bool, bool>falseを返します。

私自身の実装は

template<class T1, class T2>
bool is_one_of<T1, T2>() {
    return std::is_same<T1, T2>;
}

template<class T1, class T2, class... Ts>
bool is_one_of<T1, T2, Ts...>() {
    if (std::is_same<T1, T2>) {
        return true;
    }
    else {
        return is_one_of<T1, Ts...>();
    }
}

このチェックは私には一般的のようですので、標準ライブラリにそのような関数がすでにあるかどうか疑問に思います。

38
Yixing Liu

独自の実装での1つの問題は、C++では関数テンプレートの部分的な特殊化が許可されないことです。

再帰的な関数呼び出しの代わりに、フォールド式(C++ 17で導入)を使用できます。

template<class T1, class... Ts>
constexpr bool is_one_of() noexcept {
    return (std::is_same_v<T1, Ts> || ...);
}

C++ 11を使用している場合、折り返し式とstd::disjunctionは使用できません。実装できますis_one_of このような:

template<class...> struct is_one_of: std::false_type {};
template<class T1, class T2> struct is_one_of<T1, T2>: std::is_same<T1, T2> {};
template<class T1, class T2, class... Ts> struct is_one_of<T1, T2, Ts...>: std::conditional<std::is_same<T1, T2>::value, std::is_same<T1, T2>, is_one_of<T1, Ts...>>::type {};
40
Shaoyu Chen

std::disjunctionを使用して、不要なテンプレートのインスタンス化を回避することもできます。

template <class T0, class... Ts>
constexpr bool is_one_of = std::disjunction_v<std::is_same<T0, Ts>...>;

一致するタイプが見つかると、残りのテンプレートはインスタンス化されません。対照的に、fold式はそれらすべてをインスタンス化します。これは、ユースケースに応じて、コンパイル時間に大きな違いをもたらす可能性があります。

30
L. F.

タイプTがパラメーターパックTsの中にあるかどうかを確認します。

template<class T0, class... Ts>
constexpr bool is_one_of = (std::is_same<T0, Ts>{}||...);

テンプレート変数。

代替:

template<class T0, class... Ts>
constexpr std::integral_constant<bool,(std::is_same<T0, Ts>{}||...)> is_one_of = {};

微妙な違いがあります。

他の回答は、この特定の問題を簡潔かつ簡潔に解決するためのいくつかの正しい解決策を示しています。 この特定の問題にはお勧めしませんの解決策を次に示しますが、別の手法を示しています:constexpr関数では、コンパイル時に結果を計算するために単純なforループと単純なロジックを使用できます時間。これにより、再帰、および試行されたOPのコードの部分テンプレート特殊化を取り除くことができます。

#include <initializer_list>
#include <type_traits>

template<class T, class... Ts>
constexpr bool is_one_of() {
  bool ret = false;

  for(bool is_this_one : {std::is_same<T, Ts>::value...}) {
    ret |= is_this_one;// alternative style: `if(is_this_one) return true;`
  }

  return ret;
}

static_assert(is_one_of<int, double, int, float>(), "");
static_assert(!is_one_of<int, double, char, bool, bool>(), "");

少なくともC++ 14が必要です。

2
Julius