根据模板参数切换案例数量

问题描述 投票:0回答:1

我需要一种有效的方法将 0 到 N-1 范围内的运行时动态 int 转换为模板参数。

也就是说,从逻辑上讲,我想创建一个

switch
,在
0
N-1
之间切换数字。
N
是一个模板参数,因此案例数在编译时是固定的,但它依赖于模板参数,所以我不能只使用普通的开关。

目标是为每种情况调用模板 lambda,其中切换的数字作为模板参数传递给 lambda。即,我想从动态数字变为静态模板参数。所以在伪代码中,我想达到这样的效果:

template<size_t N, typename Lambda>
auto switchOverN(int n, Lambda lambda) {
   assert(n < N && n >= 0);
   switch (n) {
      case 0: return lambda<0>();
      case 1: return lambda<1>();
      ...
      case N-1: return lambda<n-1>();
   }
}

解决方案应该只使用模板,而不使用宏。当然,由于案例数量不同,我不能使用正常的

switch

我怎样才能实现这个目标?这是我到目前为止所拥有的。

我使用

std::variant
std::make_index_sequence
std::integral_constant
的组合来给出 0 到 N-1 之间所有积分常数的变体:

template<size_t I>
struct IndexVariantHelper {
   template<std::size_t... I>
   std::variant<std::integral_constant<int, I>...> toVariant(std::index_sequence<I...>) { return {}; }

   typename type = decltype(toVariant(std::make_index_sequence<I>()));
}

所以现在我可以使用

IndexVariantHelper<N>::type
来获取索引序列的变体,并且我可以使用
std::visit
来执行切换。所以我几乎完成了...:

template<size_t N, typename Lambda>
auto switchOverN(int n, Lambda lambda) {
   typename IndexVariantHelper<N>::type switcher = ... // Here's the missing part
   return std::visit([&]<typename Idx>(const Idx&) {
      constexpr size_t i = Idx::value;
      return lambda<i>();
   }, switcher);

现在可以完成切换了,太好了!好消息是生成的代码非常高效。编译器可以查看所有模板,并确实为开关生成非常有效的代码。它甚至可以不断地折叠它——当然取决于 lambda。这是一个例子:https://godbolt.org/z/v31sdKWv1

我唯一剩下的问题是如何将动态输入

n
放入变体中。我已经没有想法了。

c++ templates lambda switch-statement variadic-templates
1个回答
0
投票

函子数组可以完成这项工作

template <std::size_t N>
auto toIntegralConstantVariant(std::size_t n)
{
    return [&]<std::size_t... Is>(std::index_sequence<Is...>){
        return std::array{
            +[]() -> std::variant<std::integral_constant<size_t, Is>...>{
                return std::integral_constant<size_t, Is>{};
            }...
    }[n]();
    }(std::make_index_sequence<N>{});
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.