从整数范围模板参数创建笛卡尔积

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

我正在与第三方库合作,该库提供了一个

Numeric
类,该类必须使用精度和比例参数进行模板化。不幸的是,在我创建的库的上下文中,直到运行时才知道精度和比例,因此我需要创建这些值到各自模板化函数的运行时映射。

数字库支持最多 38 位十进制数字,因此理论上我需要创建以下形式的映射:

mapping = {
  <38, 38>: []() { // do something with Numeric<38, 38> ... },
  <38, 37>: []() { // do something with Numeric<38, 37> ... },
  ...
  <37, 37>: []() { // do something with Numeric<38, 37> ... },
  <37, 36>: []() { // do something with Numeric<38, 37> ... },
  ...
}

对于 (0, 38] 范围内的所有精度和小数位数参数,其中

scale <= precision

这是我创建的代码,忽略 std::function 映射值的实现并暂时使用较小的参数包:

using funcMapType = std::map<std::pair<int, int>, std::function<void(void)>>;

template <int P, int S, int... Rest> struct NumericCreatorInserter {
  static void insert(funcMapType &func_map) {
    NumericCreatorInserter<P, P>::insert(func_map);
    NumericCreatorInserter<P, S>::insert(func_map);
    NumericCreatorInserter<P, Rest...>::insert(func_map);
    NumericCreatorInserter<S, Rest...>::insert(func_map);
  }
};

template <int Precision, int Scale>
struct NumericCreatorInserter<Precision, Scale> {
  static void insert(funcMapType &func_map) {
    std::cout << "Precision is: " << Precision << " and scale is: " << Scale
              << std::endl;
    func_map.emplace(std::make_pair(Precision, Scale), [](void) { return; });
  }
};

static funcMapType initializeNumericCreatorMap() {
  funcMapType numeric_creators;
  NumericCreatorInserter<3, 2, 1, 0>::insert(numeric_creators);
  return numeric_creators;
};

在运行时调试它,我得到以下信息:

Precision is: 3 and scale is: 3
Precision is: 3 and scale is: 2
Precision is: 3 and scale is: 3
Precision is: 3 and scale is: 1
Precision is: 3 and scale is: 0
Precision is: 1 and scale is: 0
Precision is: 2 and scale is: 2
Precision is: 2 and scale is: 1
Precision is: 2 and scale is: 0
Precision is: 1 and scale is: 0

我期待看到成对的 (3, 3)、(3, 2)、(3, 1)、(3, 0)、(2, 2)、(2, 1) 等...

我想我理解我的代码的问题 - 当 P = 3、S = 1 和时,以 (3, 3)、(3, 1)、(3, 0) 和 (1, 0) 开头的序列发生Rest...=0,发生在函数第一次递归调用期间

话虽如此,我正在努力解决如何用 C++ 表达我想要实现的目标。我是否应该引入另一个模板专业化才能使其发挥作用?

理想情况下,我正在寻找适用于 C++17 的解决方案

c++ templates c++17
1个回答
0
投票

将运行时值转换为编译时值的一种方法是使用

std::variant
:

template <std::size_t N>
constexpr auto to_integral_variant(std::size_t n)
{
    return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
        using ResType = std::variant<std::integral_constant<std::size_t, Is>...>;
       ResType all[] = {ResType{std::integral_constant<std::size_t, Is>{}}...};
       return all[n];
    }(std::make_index_sequence<N>());
}

然后,使用

std::visit
进行调度:

auto foo(std::size_t prec, std::size_t scale)
{
    return std::visit([](auto P, auto S) {
        return func<P(), S()>();
    }, to_integral_variant<MAX>(prec), to_integral_variant<MAX>(scale));
}

演示

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