类似结构的元组/在结构中包装一组可变的模板参数值
Structural tuple-like / Wrapping a variadic set of template parameters values in a struct
我发现自己 wanting/needing 使用可变复合类型作为模板参数。不幸的是,std::tuple<>
不是结构类型,这使得显而易见的方法行不通:
#include <tuple>
template<typename... Ts>
struct composite {
std::tuple<Ts...> operands;
};
template<auto v>
void foo() {}
int main() {
constexpr composite tmp{std::make_tuple(1,2,3)};
foo<tmp>(); // <----- Nope!
}
有没有一种合理的方法来构建这样一个结构类型的复合体?
由于孤立的 MCVE 可以简单地解决为“只需 foo()
可变参数模板”,这里有一个更具代表性的例子:
#include <concepts>
#include <tuple>
template <typename T, template <typename...> typename U>
concept TemplatedConfig = requires(T x) {
{ U(x) } -> std::same_as<T>;
// A few more things identifying T as a valid config
};
template<auto Config>
struct proc;
// Basic
struct Basic {};
template<Basic v>
struct proc<v> {
constexpr int foo() { return 0; }
};
// Annotated
template<typename T>
struct Annotated {
T v;
int annotation;
};
template<TemplatedConfig<Annotated> auto v>
struct proc<v> {
constexpr int foo() { return 1; }
};
// ... more config / specialization pairs ...
// Composite
template<typename... Parts>
struct Composite {
std::tuple<Parts...> parts;
};
template<TemplatedConfig<Composite> auto v>
struct proc<v> {
constexpr int foo() { return 2; }
};
int main() {
constexpr Basic a = Basic{};
constexpr Annotated b{a, 12};
constexpr Composite c{std::make_tuple(a, b)};
static_assert(proc<a>{}.foo() == 0);
static_assert(proc<b>{}.foo() == 1);
static_assert(proc<c>{}.foo() == 2); <----- :(
}
编辑: 如果有人好奇基于已接受答案的(几乎)完全实现的元组 class 是什么样的:https://gcc.godbolt.org/z/ThaGjbo67
创建您自己的类似元组的结构class?
类似于:
template <std::size_t I, typename T>
struct tuple_leaf
{
T data;
};
template <typename T> struct tag{ using type = T; };
template <typename Seq, typename...>
struct tuple_impl;
template <std::size_t... Is, typename... Ts>
struct tuple_impl<std::index_sequence<Is...>, Ts...> : tuple_leaf<Is, Ts>...
{
constexpr tuple_impl(Ts... args) : tuple_leaf<Is, Ts>{args}... {}
};
template <typename T, std::size_t I> constexpr const T& get(const tuple_leaf<I, T>& t) { return t.data; }
template <typename T, std::size_t I> constexpr T& get(tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T> constexpr const T& get(const tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T> constexpr T& get(tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T>
tag<T> tuple_element_tag(const tuple_leaf<I, T>&);
template <std::size_t I, typename Tuple>
using tuple_element = decltype(tuple_element_tag<I>(std::declval<Tuple>()));
template <std::size_t I, typename Tuple>
using tuple_element_t = typename tuple_element<I, Tuple>::type;
template <typename ... Ts>
using tuple = tuple_impl<std::make_index_sequence<sizeof...(Ts)>, Ts...>;
我发现自己 wanting/needing 使用可变复合类型作为模板参数。不幸的是,std::tuple<>
不是结构类型,这使得显而易见的方法行不通:
#include <tuple>
template<typename... Ts>
struct composite {
std::tuple<Ts...> operands;
};
template<auto v>
void foo() {}
int main() {
constexpr composite tmp{std::make_tuple(1,2,3)};
foo<tmp>(); // <----- Nope!
}
有没有一种合理的方法来构建这样一个结构类型的复合体?
由于孤立的 MCVE 可以简单地解决为“只需 foo()
可变参数模板”,这里有一个更具代表性的例子:
#include <concepts>
#include <tuple>
template <typename T, template <typename...> typename U>
concept TemplatedConfig = requires(T x) {
{ U(x) } -> std::same_as<T>;
// A few more things identifying T as a valid config
};
template<auto Config>
struct proc;
// Basic
struct Basic {};
template<Basic v>
struct proc<v> {
constexpr int foo() { return 0; }
};
// Annotated
template<typename T>
struct Annotated {
T v;
int annotation;
};
template<TemplatedConfig<Annotated> auto v>
struct proc<v> {
constexpr int foo() { return 1; }
};
// ... more config / specialization pairs ...
// Composite
template<typename... Parts>
struct Composite {
std::tuple<Parts...> parts;
};
template<TemplatedConfig<Composite> auto v>
struct proc<v> {
constexpr int foo() { return 2; }
};
int main() {
constexpr Basic a = Basic{};
constexpr Annotated b{a, 12};
constexpr Composite c{std::make_tuple(a, b)};
static_assert(proc<a>{}.foo() == 0);
static_assert(proc<b>{}.foo() == 1);
static_assert(proc<c>{}.foo() == 2); <----- :(
}
编辑: 如果有人好奇基于已接受答案的(几乎)完全实现的元组 class 是什么样的:https://gcc.godbolt.org/z/ThaGjbo67
创建您自己的类似元组的结构class? 类似于:
template <std::size_t I, typename T>
struct tuple_leaf
{
T data;
};
template <typename T> struct tag{ using type = T; };
template <typename Seq, typename...>
struct tuple_impl;
template <std::size_t... Is, typename... Ts>
struct tuple_impl<std::index_sequence<Is...>, Ts...> : tuple_leaf<Is, Ts>...
{
constexpr tuple_impl(Ts... args) : tuple_leaf<Is, Ts>{args}... {}
};
template <typename T, std::size_t I> constexpr const T& get(const tuple_leaf<I, T>& t) { return t.data; }
template <typename T, std::size_t I> constexpr T& get(tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T> constexpr const T& get(const tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T> constexpr T& get(tuple_leaf<I, T>& t) { return t.data; }
template <std::size_t I, typename T>
tag<T> tuple_element_tag(const tuple_leaf<I, T>&);
template <std::size_t I, typename Tuple>
using tuple_element = decltype(tuple_element_tag<I>(std::declval<Tuple>()));
template <std::size_t I, typename Tuple>
using tuple_element_t = typename tuple_element<I, Tuple>::type;
template <typename ... Ts>
using tuple = tuple_impl<std::make_index_sequence<sizeof...(Ts)>, Ts...>;