我正在与第三方库合作,该库提供了一个
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 的解决方案
将运行时值转换为编译时值的一种方法是使用
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));
}