动态调度模板函数? [英] Dynamic dispatching of template functions?

查看:140
本文介绍了动态调度模板函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在运行时决定调用哪个模板函数?
类似的东西:

Is it possible to decide in run-time which template function to call? Something like:

template<int I>
struct A {
    static void foo() {/*...*/}
};

void bar(int i) {
    A<i>::f();   // <-- ???
}


推荐答案

桥接编译时和运行时处理模板时访问变种类型。这就是通用图像库(可用作Boost.GIL或独立)。它通常采取以下形式:

A typical 'trick' to bridge compile time and runtime when dealing with templates is visiting a variant type. That's what the Generic Image Library (available as Boost.GIL or standalone) does for instance. It typically takes the form of:

typedef boost::variant<T, U, V> variant_type;
variant_type variant = /* type is picked at runtime */
boost::apply_visitor(visitor(), variant);

其中 visitor 是一个多态函子转发到模板:

where visitor is a polymorphic functor that simply forwards to the template:

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 的元函数也允许在类型列表上进行计算。

This has the nice design that the list of types that the template will/can be instantiated with (here, the variant_type type synonym) is not coupled to the rest of the code. Metafunctions like boost::make_variant_over also allows computations over the list of types to use.

可用于非类型参数,您需要手动展开访问,这不幸意味着代码不可读/可维护。

Since this technique is not available to non-type parameters, you need to 'unroll' the visitation by hand, which unfortunately means the code is not as readable/maintainable.

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
    }
}


b $ b




在上面的开关中处理重复的通常方法是(ab)使用预处理器。使用Boost.Preprocessor的(未测试的)示例:


The usual way to deal with the repetition in the above switch is to (ab)use the preprocessor. An (untested) example using 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

更好地为 LIMIT 找到好的自记档名称(不会伤害 PASTE ),并将上述代码生成限制为只有一个网站。

Better find good, self-documenting names for LIMIT (wouldn't hurt for PASTE either), and limit the above code-generation to just one site.

David的解决方案和您的意见:

Building from David's solution and your comments:

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)。您可以添加一个图层来隐藏该调用的丑陋:

then to call bar: bar(i, typename build_indices<N>::type()) where N would be your constant-time constant, sizeof...(something). You can add a layer to hide the 'ugliness' of that call:

template<int N>
void
bar(int i)
{ bar(i, typename build_indices<N>::type()); }

其被称为 bar< N> c $ c>。

which is called as bar<N>(i).

这篇关于动态调度模板函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆