首页 > 解决方案 > 如何构建可以附加类型的类型的 constexpr 向量?

问题描述

我的同事挑战我构建一个TypeVector,它是编译时类似向量的容器,它可以在编译时 push_back 类型和删除类型。给定一个 constexpr TypeVector,您应该能够从TypeVector.

TypeVector 的伪代码示例用法:

consteval auto build_vector() {
   TypeVector<2> x; //TypeVector of size 2
   x.push_back(int);
   x.push_back(float);
   return x;
}

static constexpr auto my_vector = build_vector();
// Get type from first element of my_vector 
typename retrieve_type<my_vector.get<0>()>::type some_variable = 0; // equivalent to int some_variable = 0; 

// Get type from second element of my_vector 
typename retrieve_type<my_vector.get<1>()>::type some_variable2 = 0.0f; // equivalent to float some_variable2 = 0.0f; 

我认为最好的方法是使用std::array 问题是std::array不能存储类型但需要存储相同类型的值,所以我将类型转换为如下值:

template <typename T>
struct TypeHash{
   static constexpr char obj; // Create one obj per type
   static constexpr char* value = &obj; // This will be different for each type
   
};
template <typename T>
static constexpr char* to_value = TypeHash<T>::value;

// Now I can do to_value<int> and to_value<float> to "store" the float and int as values of type const char*
// Example usage:

template <int N>
using TypeVector<N> = std::array<const char*, N>;
consteval auto some_func() {
   TypeVector<2> x;
   x[0] = to_value<int>;
   x[1] = to_value<float>;
   return x;
}

static constexpr auto first_type = some_func()[0]; 

问题是反转这个操作:retrieve_type从伪代码创建。

我想通过模板专业化创建retrieve_type一个const char*类型映射,如下所示:

static constexpr auto first_type = some_func()[0]; // From above 

template < const char* value> struct retrieve_type {};
template <> struct retrieve_type<to_value<int>> { using type = int; };
template <> struct retrieve_type<to_value<float>> { using type = float; };


// Now I can get the actual type from first type:
typename retrieve_type<first_type>::type y = 0; // int x = 0;


这种方法存在一些问题:

  1. 我必须retrieve_type为每个现有类型创建一个专业化(不是一个大问题,我可以处理这个,但这并不理想)

  2. (更大的问题)如何retrieve_type为模板创建专业化?

template <typename T>
struct SomeTemplateClass {};
// How to create a specialisation of retrieve_type for all instantiations of SomeTemplateClass?

我怎样才能使这个工作适用于从模板实例化的类型?我可以避免retrieve_type为每种类型手动创建专业化吗?

我愿意使用任何第三方库/任何编译器特定选项。

标签: c++metaprogrammingc++20template-meta-programming

解决方案


模板可以双射映射到类型。

template<class T>
strict tag_t{using type=T;};
template<class T>
constexpr tag_t<T> tag={};

template<template<class...>class Z>
struct ztemplate{
  template<class...Ys>
  constexpr auto operator()(tag_t<Ys>...)const{
    return tag<Z<Ys...>>;
  }
};

这处理一类模板。

如果你解决了值到类型映射问题,你可以解决值到模板问题。上面的模板只是类型标签上的无状态 constexpr 函数对象。

对于非类型模板参数,您需要不同的标记类型和不同的无状态 function.objects。例如,采用 std 整数常量类型的模板可以包装采用整数值的模板,使其表现更好。

至于要输入的值,那只是一个冗长的冗长冗长的口号。

您可以在整数的平面列表中构建解析树。

每个节点都有一个值和一个子节点计数,都是 constexpr。您通过标签调度获取第一个值并映射到标签类型。如果元素的数量大于 1,则使用从整数列表生成的递归评估类型标签调用标签调度结果。

template<std::size_t I>
using index_t=std::integral_constant<std::size_t,I>;
template<std::size_t I>
constexpr index_t<I> index{};    
constexpr tag_t<int> map_to_type(index_t<0>){return {};}
constexpr ztemplate<std::vector> map_to_type(index_t<1>){return {};}
constexpr auto make_type(){
  constexpr int arr[]={1,0};
  return map_to_type(index<arr[0]>)(map_to_type(index<arr[1]>));
}
constexpr auto tag=make_type();
decltype(tag)::type vec={1,2,3};

推荐阅读