【问题标题】:Generalizing Solution To Instantiate Many Templates of a Function And Select At Runtime实例化函数的许多模板并在运行时选择的通用解决方案
【发布时间】:2016-03-09 19:00:06
【问题描述】:

我正在尝试概括以前在 SO here 上提供的解决方案,它使用 boost MPL 来实例化一个函数的许多模板并在运行时选择正确的模板。我需要的信息可能在互联网上传播,但我自己正在努力拼凑一个可行的解决方案。为了便于阅读,这里是之前解决方案的复制粘贴:

#include <iostream>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/at.hpp>

namespace mpl = boost::mpl;

template<int index1, int index2, int index3> void execKernel()
{
    std::cout << "Kernel called with " << index1 << "/" << index2 << "/" << index3 << std::endl;
}

typedef void (*FPTR)();
FPTR ptr[512];

struct NIL
{
public:
    static const int value = 0;
};

template<typename Seq, typename T1, typename T2 = NIL> class MakeSequenceImpl
{
public:
    template<typename T> void operator()(T)
    {
        typedef MakeSequenceImpl<typename mpl::push_back<Seq,T>::type,T2> RunSeq;
        mpl::for_each<T1>( RunSeq() );
    }
};

template<typename Seq> class MakeSequenceImpl<Seq, NIL, NIL>
{
public:
    template<typename T> void operator()(T)
    {
        typedef typename mpl::push_back<Seq,T>::type FinalSeq;

        int index = mpl::at<FinalSeq,mpl::int_<0> >::type::value * 64
                + mpl::at<FinalSeq,mpl::int_<1> >::type::value * 8
                + mpl::at<FinalSeq,mpl::int_<2> >::type::value;

        ptr[index] = execKernel<mpl::at<FinalSeq,mpl::int_<0> >::type::value, mpl::at<FinalSeq,mpl::int_<1> >::type::value, mpl::at<FinalSeq,mpl::int_<2> >::type::value>;
    }
};


template<typename T0, typename T1, typename T2> class MakeSequence
{
public:
    typedef mpl::vector_c<int> Seq;

    MakeSequence()
    {
        typedef MakeSequenceImpl<Seq, T1, T2> RunSeq;
        mpl::for_each<T0>( RunSeq() );
    }
};


void callWrapper( int i, int j, int k )
{
    ptr[i*64+j*8+k]();
}

typedef mpl::vector_c< int, 0, 1, 2, 3, 4, 5, 6, 7 > list1;
typedef mpl::vector_c< int, 0, 1, 2, 3, 4, 5, 6, 7 > list2;
typedef mpl::vector_c< int, 0, 1, 2, 3, 4, 5, 6, 7 > list3;

int main()
{
    MakeSequence<list1,list2,list3> frontend;

    int i,j,k;

    std::cin >> i;
    std::cin >> j;
    std::cin >> k;

    callWrapper(i,j,k);
}

我想将其概括为将“execKernel”作为模板参数传递给“MakeSequence”。我有很多像“execKernel”这样的函数,它们都采用模板参数的数量和相同的类型(都采用 3 个整数模板参数,0-7)。

为此,最终特化“MakeSequenceImpl”中运算符定义的最后一行需要在等号的两侧进行泛化。该语句的左侧是一个函数指针数组。我试图将其概括为所有函数都采用相同的模板参数,但函数参数不同,因此需要以某种方式传入函数指针数组。等号右侧是函数模板实例化。这部分需要传入特定的函数模板,但我发现如果不使用仿函数,就无法将未实例化的模板函数作为模板参数传递。

总而言之,我希望向下概括“MakeSequence”,以便函数指针数组和函数模板本身作为参数传入。我很高兴为每个特定函数静态定义函数指针和函数指针数组。也可以概括这些(例如,一个包含所有函数的所有函数指针的函数指针的大列表),但这是次要问题。

感谢任何人提供的任何帮助。顺便说一句,我需要继续使用 C++98/03 并提升。没有 C++11 或 14。

【问题讨论】:

    标签: c++ templates boost


    【解决方案1】:

    我通常会想到变体 + 访客:

    Live On Coliru

    #include <boost/variant.hpp>
    
    // for demo types
    #include <vector>
    #include <iostream>
    
    // some overloads and templates:
    template <typename V>
    void foo(std::vector<V> const&) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    
    void foo(int)                   { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    void foo(std::string const&)    { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    
    // a generic wrapper that instantiates 3 versions 
    // and picks the right one at runtime:
    void generic_foo(boost::variant<std::string const&, int, std::vector<double> const&> param) {
        // dispatch
        boost::apply_visitor([](auto&& p) { foo(p); }, param);
    }
    
    int main() {
        generic_foo("hello world");
        generic_foo(std::vector<double> {0.1, 0.2, 0.3});
        generic_foo(42);
    }
    

    打印

    void foo(const string&)
    void foo(const std::vector<_RealType>&) [with V = double]
    void foo(int)
    

    对于 C++03

    用更详细的东西替换 lambda:

    namespace detail {
        struct generic_foo_vis {
            typedef void result_type;
            template <typename T> void operator()(T const& stuff) const { return foo(stuff); }
            template <typename T> void operator()(T& stuff)       const { return foo(stuff); }
        };
    }
    
    // a fixed wrapper that instantiates 3 versions and picks the right one at runtime:
    void generic_foo(boost::variant<std::string const&, int, std::vector<double> const&> param) {
        // dispatch
        boost::apply_visitor(detail::generic_foo_vis(), param);
    }
    

    Live On Coliru

    【讨论】:

    • 制作 c++03 证明样本。完成:c++03 Live On Coliru
    • 这需要我一点时间来消化并弄清楚它是否适用,但让我印象深刻的是与原始 Q/A 明显不同的是,这里的模板类型正在模板化函数参数.在原始 Q/A 中,模板类型没有模板化参数(实际上,我没有模板化函数参数)。我将它用于 myFunction(unrelated, fun, parameters) 之类的东西,其中 i、j 和 k 分别从 0-7 开始。
    • 嗯。我确实没有注意到样本。您可以可能使用类似的技术(使用 std::integral_constant),但我不确定我是否会推荐它。让我考虑一下
    • 感谢您的帮助!我目前正在阅读有关 boost 变体和访问者的信息,因为它们通常对了解它们很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 2012-07-09
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    相关资源
    最近更新 更多