模板函数的动态调度
Dynamic dispatching of template functions?
是否可以在运行时决定调用哪个模板函数?类似于:
template<int I>
struct A {
static void foo() {/*...*/}
};
void bar(int i) {
A<i>::f(); // <-- ???
}
在处理模板时,连接编译时和运行时的一个典型"技巧"是访问变体类型。例如,Generic Image Library(可作为Boost.GIL或单机版提供(就是这样做的。它通常采用以下形式:
typedef boost::variant<T, U, V> variant_type;
variant_type variant = /* type is picked at runtime */
boost::apply_visitor(visitor(), variant);
其中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&);
};
这有一个很好的设计,即模板将/可以实例化的类型列表(这里是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
}
}
处理上述切换中重复的常见方法是(ab(使用预处理器。使用Boost的(未经测试的(示例。预处理器:
#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
最好为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]();
}
然后调用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()); }
称为CCD_ 10。
您可以创建一个查找表,然后动态使用它,具体取决于您想要做什么(即是否有少量有限的实例化需要使用?(。对于完全手动的方法,使用选项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]();
}
当然,我为这个例子选择了最简单的选项。如果所需的数字不是连续的或基于零,则可能更喜欢std::map<int, void (*)(void) >
而不是数组。如果要使用的不同选项的数量较大,则可能需要添加代码来自动输入模板,而不是手动键入所有模板。。。但是您必须考虑模板的每个实例化都会创建一个新的函数,并且您可能需要检查是否确实需要它。
EDIT:我写了一篇文章,只使用C++03功能实现了相同的初始化,这篇文章似乎太长了,无法给出答案。
Luc Danton在这里写了一个有趣的答案,其中包括使用C++0x结构初始化查找表。我不太喜欢这个解决方案,因为它更改了接口以需要额外的参数,但这可以通过中间调度器轻松解决。
不,模板是编译时的特性,而i
在编译时是未知的,所以这是不可能的。CCD_ 13应该适应于类似CCD_。
否
模板实现编译时多态性,而不是运行时多态性。
模板参数必须在编译时已知。所以编译器无法通过A<i>::foo()
。
如果你想变通,那么你必须使bar()
也成为template
:
template<int i>
void bar() {
A<i>::f(); // ok
}
为此,您必须在编译时知道bar()
的参数。
- 动态调度到模板函数C++
- 动态构造函数中的新字符 [] 抛出"损坏的顶部大小";
- 有没有办法在 c++ 中按函数的名称动态调用函数
- openMp 动态调度与按处理时间排序任务时的 LPT 调度相同吗?
- (C++);动态决定函数的类型(派生类)
- 动态创建函数并获取指针
- 是否会动态调度在具有 vtable 的类上调用非虚函数
- 如何从 c++ 调用动态库函数
- 带有模板类和动态调度的C 共享_POINTER
- 使用模板或泛型动态命名函数
- 动态推导函数的返回类型
- 动态定义函数返回类型
- C++动态定义函数
- C++或D:在没有动态调度的情况下解耦类的习惯用法
- C++动态调度和后期绑定有什么区别
- 动态调度是如何在程序集中发生的
- visual 阻止在C++库中动态使用函数
- 为什么动态调度比 openmp 中的静态调度更快
- 模板函数的动态调度
- 动态调度哪些函数