假设我们有
等功能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行;但我可以做更好的事情,而不是那么做宏观的事情吗?是否可以编写类似上面 general 的内容,并且适用于每个可变参数模板和固定值的常量值?
备注:
答案 0 :(得分:6)
你可以创建一个函数指针表:
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(*)()>
或其他东西。
答案 1 :(得分:3)
在这种情况下,我喜欢构建一个函数指针的静态表,其中一个动态参数决定调用哪一个。以下是在函数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;
}