How can I check type T is among parameter pack Ts...?

You can also use std::disjunction to avoid unnecessary template instantiation:

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

After a matching type is found, the remaining templates are not instantiated. In contrast, a fold expression instantiates all of them. This can make a significant difference in compile time depending on your use case.


In your own implementation, one issue is that C++ doesn't allow partial specialization on function templates.

You can use the fold expression (which is introduced in C++17) instead of recursive function call.

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

If you are using C++11 where fold expression and std::disjunction are not available, you can implement is_one_of like this:

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 {};