避免运行时到编译时数值参数转换的代码重复
Avoiding code duplication for runtime-to-compile-time numeric parameter translation
假设我们有这样的函数
template <typename T, unsigned N> void foo();
为简单起见,假设我们知道只有(常量(值N_1
,N_2
... N_k
对N
有效。
现在,假设我想使该编译时参数成为运行时参数,使用 foo()
作为黑盒,即实现:
template <typename T> void foo(unsigned n);
通过拨打foo<,>()
电话。我应该怎么做?显然,我可以写:
template <typename T> void foo(unsigned n) {
switch(n) {
case N_1 : foo<T, N_1>(); break;
case N_2 : foo<T, N_2>(); break;
// etc. etc.
case N_k : foo<T, N_k>(); break;
}
}
。但这让我觉得很脏。我想我可以使用 MAP(( 元宏来生成这些 k 行;但是我能做任何更好、更少宏观的事情来实现同样的目标吗?是否可以编写类似上述通用的东西,并且适用于每个可变参数模板和固定的常量值序列?
笔记:
- C++11/14/17 的具体建议显然是受欢迎的。
- N不一定是连续的,也不小,也不一定是排序的,例如假设N_2 = 123456789,N_5 = 1。
你可以做一个函数指针表:
using F = void(*)();
template <class T, class >
struct Table;
template <class T, size_t... Is>
struct Table<T, std::index_sequence<Is...> > {
static constexpr F fns[] = {
foo<T, Is>...
};
};
template <class T, size_t... Is>
constexpr F Table<T, std::index_sequence<Is...> >::fns[sizeof...(Is)];
然后只需调用您想要的那个:
template <class T, size_t N>
struct MakeTable : Table<T, std::make_index_sequence<N>> { };
template <typename T>
void foo(unsigned n) {
MakeTable<T, MaxN>::fns[n]();
}
<小时 />如果N_k
不是连续的,那么我们可以使用 lambda 进行内联参数解包:
template <class T>
void foo(unsigned n) {
using seq = std::index_sequence<N_1, N_2, ..., N_k>;
indexer(seq)([n](auto i){
if (n == i) {
f<T, i>();
}
});
}
<小时 />如果以上太慢,那么我想只需手动构建std::unordered_map<unsigned, void(*)()>
什么的。
在这种情况下,我喜欢构建一个函数指针的静态表,用一个动态参数决定调度到哪个。下面是在函数中实现此目的的实现 foo_dynamic
.对于此函数,您可以指定要支持的N
的最大值,并使用一些递归模板生成函数指针的静态表。然后,使用动态参数取消引用到此表中。
using ftype = void (*)();
template <typename T, unsigned N> void foo()
{
std::cout << N << std::endl;
}
template <typename T, unsigned max>
struct TablePopulator
{
static void populateFTable(ftype* table)
{
table[max] = foo<T,max>;
TablePopulator<T,max-1>::populateFTable(table);
}
};
template <typename T>
struct TablePopulator<T, 0>
{
static void populateFTable(ftype* table)
{
table[0] = foo<T,0>;
}
};
template<typename T, unsigned max_N>
std::array<ftype, max_N>& initTable()
{
static std::array<ftype, max_N> table;
TablePopulator<T, max_N-1>::populateFTable(table.data());
return table;
}
template<typename T, unsigned max_N>
void foo_dynamic(unsigned actualN)
{
static auto ftable = initTable<T, max_N>();
if(actualN >= max_N)
throw std::runtime_error("Max param exceeded");
ftable[actualN]();
}
int main()
{
foo_dynamic<int, 10>(1);
foo_dynamic<int, 10>(5);
return 0;
}
编辑:鉴于问题编辑中的约束,这里有一种方法是手动指定有效索引的,它使用unordered_map
而不是数组:
using ftype = void (*)();
template <typename T, unsigned N> void foo()
{
std::cout << N << std::endl;
}
template<typename T, size_t ... Indices>
void foo_dynamic_indices(size_t actual_index)
{
static std::unordered_map<size_t, ftype> fmap = {{Indices, foo<T,Indices>}...};
auto fIt = fmap.find(actual_index);
if(fIt == fmap.end())
throw std::runtime_error("Index not found");
fIt->second();
}
int main()
{
foo_dynamic_indices<int, 0, 3, 400, 1021, 10000000>(10000000);
foo_dynamic_indices<int, 0, 3, 400, 1021, 10000000>(4); //Exception
return 0;
}
相关文章:
- C++转换参数初始化问题
- C2664 无法从'initializer list'转换参数
- 隐式可转换参数,但属于引用类型
- 传递到函数(C )时转换参数
- 了解错误 C2664:无法转换参数 1
- 错误 C2664:无法从'NvPhysicalGpuHandle'转换参数 1
- Unicode 字符问题/转换参数
- 在运行时根据某些元数据强制转换参数包值
- 错误 C2664:"errno_t wcstombs_s(size_t *,字符 *,size_t,常量 wchar_t *,size_t)":无法转换参数 4
- 错误C2664:无法转换参数错误
- 无法转换参数错误
- Boost.python自动转换参数
- "尝试升级使用已弃用的转换参数指定的输入文件"是什么意思?
- 是否可以在函数模板中转换参数C++?
- 错误C2664:无法转换参数(指纹传感器检测)
- 无法转换参数 - 模板错误
- 编译zxing时,Libconv无法转换参数
- C++ 无法转换参数
- std::p air<_Ty1,_Ty2>::p air<_Ty1,_Ty2>& 无法转换参数
- 无法转换参数-转换丢失限定符