首先,定义一个C风格的可变参数函数
static bool value_in (T val, T vals, ...)
前面的逗号...
是可选的。
So your
static bool value_in(T val, T vals...)
定义两个非可变参数(val
and vals
) 和一个未命名的可变序列。
如何编写接受任意数量的相同类型参数的声明?
有很多方法,但恕我直言,有缺点
一种可能的方法是使用 SFINAE:您可以强制变量类型等于第一种类型。
以下是使用模板折叠的C++17可能的解决方案
template <typename T, typename ... Ts>
std::enable_if_t<(std::is_same<T, Ts>::value && ...), bool>
value_in (T val, Ts ... vals)
{
const std::unordered_set<T> allowed {val, vals ... };
return allowed.find(val) != allowed.end();
}
您也可以在 C++11/C++14 中开发此解决方案,但稍微复杂一些。
缺点:Ts...
类型是推导出来的,并且它们必须完全相同T
type.
因此,例如,如果您想要一个接受列表的函数std::string()
,你不能用char const *
value_in(std::string{"abc"}, "123");
because T
, std::string
, 不同于Ts...
, char const *
,并且 SFINAE 未启用value_in
.
您可以使用std::is_convertible
代替std::is_same
但我建议另一种方法,分两步。
首先,您需要一个自定义类型特征(带有using
helper)从列表中选择第一个类型
template <typename T, typename ...>
struct firstType
{ using type = T; };
template <typename T, typename ... Ts>
using firstType_t = typename firstType<T, Ts...>::type;
现在您可以编写第一步value_in()
拦截所有值,检测所有类型(无限制)并将它们传递给第二步函数,如下所示
template <typename T, typename ... Ts>
bool value_in (T val, Ts ... vals)
{ return value_in_helper<T, Ts...>(val, vals...); }
第二步函数改变所有Ts...
输入T
using firstType
template <typename T, typename ... Ts>
bool value_in_helper (T val, firstType_t<T, Ts> ... vals)
{
const std::unordered_set<T> allowed {val, vals ... };
return allowed.find(val) != allowed.end();
}
此解决方案与 C++11 兼容。
缺点:你需要第二步。
优点(恕我直言):该解决方案通过声明接收的第二步函数T
类型,因此也接受可转换为的参数T
.
即:该解决方案也接受
value_in(std::string{"abc"}, "123");
因为不再需要了"123"
正是一个std::string
;也可以转换为std::string
.