如何检查类型T是否在参数包Ts中?

Yix*_*Liu 38 c++ variadic-templates

我想编写一个函数,如果T是其中之一,则返回trueTs...

template<class T, class... Ts>
bool is_one_of<T, Ts...>();
Run Code Online (Sandbox Code Playgroud)

例如,is_one_of<int, double, int, float>收益trueis_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...>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这种检查对我来说似乎很常见,所以我想知道标准库中是否已经有这样的功能。

Sha*_*hen 40

在您自己的实现中,一个问题是C ++不允许对函数模板进行部分专业化。

您可以使用fold表达式(在C ++ 17中引入)而不是递归函数调用。

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

如果您使用的C ++ 11中没有fold表达式并且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 {};
Run Code Online (Sandbox Code Playgroud)

  • 也可能是变量而不是函数:) (2认同)

L. *_* F. 30

您还可以使用std::disjunction以避免不必要的模板实例化:

template <class T0, class... Ts>
constexpr bool is_one_of = std::disjunction_v<std::is_same<T0, Ts>...>;
Run Code Online (Sandbox Code Playgroud)

找到匹配类型后,其余模板不会被实例化。相反,fold表达式将所有实例实例化。根据您的用例,这可能在编译时间上产生重大差异。

  • @ShaoyuChen Yep。想法是,OP想知道“标准库中已经有这样的功能” (3认同)

Yak*_*ont 10

检查类型T是否在参数包Ts中:

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

模板变量。

选择:

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

两者之间有细微的差异。