在参数包和变量模板上解包元组的语法



我有一个示例参数包函数:

template<typename T, typename ... Args>
constexpr bool all_values_equal(T first, Args... args) {
return ((first == args) && ...);
}
static_assert(all_values_equal(1, 1, 1.0));

我经常使用std::tuple,因为我喜欢使用模板。提取类型、切片类型和其他排列。

如何使用std::tuple调用此函数?

template<typename ... Args>
constexpr bool all_values_equal(std::tuple<Args...> tuple) {
return /* ??? */ ;
}
static_assert(all_values_equal(std::make_tuple(1, 1, 1.0)));

我也想知道没有参数的可变模板函数的情况:

template<typename T, typename ... Args>
constexpr bool all_types_equal() {
return (std::is_same_v<T, Args> && ...);
}
template <template<typename ... Args> class Tuple>
constexpr bool all_types_equal() {
return /* ??? */ ;
}
static_assert(all_types_equal<int, int>());
static_assert(all_types_equal<std::tuple<int, int>>());

最终,我希望能够调用所有4种变体,如下所示:

static_assert(all_values_equal(1, 1, 1.0));
static_assert(all_values_equal(std::make_tuple(1, 1, 1.0)));
static_assert(all_types_equal<int, int>());
static_assert(all_types_equal<std::tuple<int, int>>());

并且CCD_ 3函数不应当重新实现可变模板函数的逻辑。我怎样才能以一种干净和现代的方式实现这一点?

std::apply让我们用元组元素作为参数来调用一个函数。你可以把它和lambda一起使用。

template<typename ... Args>
constexpr bool all_values_equal(std::tuple<Args...> tuple) {
auto cmp = [](auto&& first, auto&&... args) {
return ((first == args) && ...);
};
return std::apply(cmp, tuple);
}

为了进行all_types_equal检查,我们可以使用部分专门化。像这样的东西。

template <typename First, typename ... Rest>
constexpr bool all_types_equal_impl = (std::is_same_v<First, Rest> && ...);;
template <typename First, typename ... Rest>
constexpr bool all_types_equal_impl<std::tuple<First, Rest...>> = (std::is_same_v<First, Rest> && ...);
template <typename... Args>
constexpr bool all_types_equal() {
return all_types_equal_impl<Args...>;
}

我们可以直接引用模板变量,所以如果我们不想,就不需要将其封装在函数中

使用std::index_sequence可以访问每个数据字段和std::tuple的每种类型。由于C++20 lambda可以被模板化,因此这允许内联拆包。

template<typename ... Args>
constexpr bool all_values_equal(std::tuple<Args...> tuple) {
constexpr auto unpack_tuple = []<typename Tuple, size_t... Ints>(Tuple tuple, std::index_sequence<Ints...>) {
return all_values_equal(std::get<Ints>(tuple)...);
};
return unpack_tuple(tuple, std::make_index_sequence<std::tuple_size_v<decltype(tuple)>>());
}
template <template<typename ... Args> class Tuple>
constexpr bool all_types_equal() {
constexpr auto unpack_tuple = []<typename Tuple, size_t... Ints>(std::index_sequence<Ints...>) {
return all_types_equal<std::tuple_element_t<Ints, Tuple>...>();
};
return unpack_tuple.template operator()<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

static_assert(all_values_equal(1, 1, 1.0));
static_assert(all_values_equal(std::make_tuple(1, 1, 1.0)));
static_assert(all_types_equal<int, int>());
static_assert(all_types_equal<std::tuple<int, int>>());
  • std::make_index_sequencestd::tuple_size_v是标准中方便的实用程序。

  • std::get<Int>(tuple)...取消打包值,std::tuple_element_t<Ints, Tuple>...取消打包类型。

  • .template operator()<Tuple>(...)允许指定模板化lambda 的模板

最新更新