Luc*_*ton 13
处理模板时桥接编译时间和运行时的典型"技巧"是访问变体类型.这就是通用映像库(可用作Boost.GIL或独立)的功能.它通常采取以下形式:
typedef boost::variant<T, U, V> variant_type;
variant_type variant = /* type is picked at runtime */
boost::apply_visitor(visitor(), variant);
Run Code Online (Sandbox Code Playgroud)
哪里visitor是一个简单转发到模板的多态仿函数:
struct visitor: boost::static_visitor<> {
template<typename T>
void
operator()(T const& t) const
{ foo(t); } // the real work is in template<typename T> void foo(T const&);
};
Run Code Online (Sandbox Code Playgroud)
这有一个很好的设计,模板将/可以实例化的类型列表(这里,variant_type类型同义词)没有耦合到代码的其余部分.元函数boost::make_variant_over也允许对要使用的类型列表进行计算.
由于这种技术不适用于非类型参数,因此您需要手动"展开"访问,遗憾的是这意味着代码不具有可读性/可维护性.
void
bar(int i) {
switch(i) {
case 0: A<0>::f(); break;
case 1: A<1>::f(); break;
case 2: A<2>::f(); break;
default:
// handle
}
}
Run Code Online (Sandbox Code Playgroud)
处理上述开关中重复的常用方法是(ab)使用预处理器.使用Boost.Preprocessor的(未经测试的)示例:
#ifndef LIMIT
#define LIMIT 20 // 'reasonable' default if nothing is supplied at build time
#endif
#define PASTE(rep, n, _) case n: A< n >::f(); break;
void
bar(int i) {
switch(i) {
BOOST_PP_REPEAT(LIMIT, PASTE, _)
default:
// handle
}
}
#undef PASTE
#undef LIMIT
Run Code Online (Sandbox Code Playgroud)
更好地找到好的,自我记录的名称LIMIT(不会伤害PASTE任何一个),并将上述代码生成限制在一个站点.
根据David的解决方案和您的意见构建:
template<int... Indices>
struct indices {
typedef indices<Indices..., sizeof...(Indices)> next;
};
template<int N>
struct build_indices {
typedef typename build_indices<N - 1>::type::next type;
};
template<>
struct build_indices<0> {
typedef indices<> type;
};
template<int... Indices>
void
bar(int i, indices<Indices...>)
{
static void (*lookup[])() = { &A<Indices>::f... };
lookup[i]();
}
Run Code Online (Sandbox Code Playgroud)
然后调用bar:bar(i, typename build_indices<N>::type())这里N将是你定时间常数sizeof...(something).您可以添加图层以隐藏该调用的"丑陋":
template<int N>
void
bar(int i)
{ bar(i, typename build_indices<N>::type()); }
Run Code Online (Sandbox Code Playgroud)
被称为bar<N>(i).
根据您想要做的事情(即是否有少量有限的实例化要使用?),您可以创建一个查找表,然后动态使用它.对于完全手动方法,使用选项0,1,2和3,您可以:
void bar( int i ) {
static void (*lookup[])(void) = { &A<0>::foo, &A<1>::foo, &A<2>::foo, &A<3>::foo };
lookup[i]();
}
Run Code Online (Sandbox Code Playgroud)
当然,我为这个例子选择了最简单的选项.如果您需要的数字不是连续的或基于零,您可能更喜欢std::map<int, void (*)(void) >而不是数组.如果要使用的不同选择的数量较大,您可能希望添加代码以自动实例化模板,而不是手动键入所有这些...但您必须考虑模板的每个实例化创建一个新的功能,你可能想检查你是否真的需要它.
编辑:我写了一篇文章,只使用C++ 03功能实现相同的初始化,它似乎太长了答案.
Luc Danton 在这里写了一个有趣的答案,其中包括使用C++ 0x构造初始化查找表.我不太喜欢这个解决方案,它改变了接口以要求额外的参数,但这可以通过中间调度程序轻松解决.