递归模板参数包编程

Recursive template parameter pack programming

本文关键字:编程 包编程 参数 递归      更新时间:2023-10-16

我是C 模板编程的新手。我想设计一个函数element,例如,例如

  1. element<3, 3, 3, 3, 3>将返回3
  2. element<3, 3, 2>将失败

    #include <iostream>
    #include <cstdlib>
    namespace meta
    {       
      template<typename T>
      constexpr T element(T x)
      {
        return x;
      }
      template<typename T, typename... Ts>
      constexpr T element(T x, Ts... xs)
      {
        constexpr T oth = element(xs...);             // $C$
        static_assert(oth == x, "element Mismatch");
        return x;
      }
      template<int... DIMS>
      void get_elements()
      {
        std::cout << "elements " << element(DIMS...); // $A$
      }
    }
    int main(int argc, char ** argv)
    {
      meta::get_elements<2, 3, 4>();                  // $B$
      static constexpr int D1 = 3, D2 = 3;
      meta::get_elements<D1, D2>();
    }
    

但是,使用

std=c++14的GCC失败

在实例化'constexpr t meta :: element(t,ts ...([带t = int;ts = {int,int}]’:

$ a $:需要‘void meta :: get_elements(([with int ... dims = {2,3,4}]’

$ b $:此处需要

$ c $:错误:‘xs#0'不是常数表达式

$ c $:错误:‘xs#1'不是常数表达式

我想利用递归以对列表中的每个模板参数执行平等检查,如果它们都相等,则返回其中一个。

参数不是 constexpr

您可以使用std::integral_constant绕过该

namespace meta
{       
  template<typename T, T V>
  constexpr std::integral_constant<T, V> element(std::integral_constant<T, V>)
  {
    return {};
  }
  template<typename T, T V, typename... Ts>
  constexpr std::integral_constant<T, V> element(std::integral_constant<T, V> x, Ts... xs)
  {
    constexpr auto oth = element(xs...);             // $C$
    static_assert(oth() == x(), "element Mismatch");
    return {};
  }
  template<int... DIMS>
  void get_elements()
  {
    std::cout << "elements " << element(std::integral_constant<int, DIMS>{}...); // $A$
  }
}

这是C 17中的一个简单解决方案:

template <int Head, int... Tail> struct element
{
    static_assert((... && (Head == Tail)), "missmatch elements");
    static constexpr auto value = Head;
};
template <int... I> constexpr auto element_v = element<I...>::value;
auto test()
{
    // element_v<3, 3, 1>; // assert fail
    constexpr int A = 3, B = 3;
    return element_v<3, 3, A, B>;
}

在Godbolt上看到它

或pre-c 17(无递归(:

#include <iostream>
#include <cstdlib>
#include <type_traits>

namespace meta
{     
  template <bool...>
  struct boolpack { };
  template <bool... Bs>
  struct all_of: std::is_same<boolpack<Bs..., true>, boolpack<true, Bs...>> { };

  template<int FIRST, int... DIMS>
  constexpr void get_elements()
  {
      static_assert(all_of<DIMS==FIRST...>::value, "!");
      std::cout << "elements " << FIRST;
  }
}
int main(int argc, char ** argv)
{
  static constexpr int D1 = 3, D2 = 3;
  meta::get_elements<D1, D2>();
  //meta::get_elements<D1, D2, 2>(); //fail
}

[见Live]

编辑all_of受JAROD42启发。