推广解决方案实例化函数的许多模板并在运行时选择

时间:2016-03-09 19:00:07

标签: c++ templates boost

我正在尝试概括先前在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&lt; Seq,NIL,NIL&gt;”中的运算符定义的最后一行需要在等号的两边进行推广。该语句的左侧是一个函数指针数组。我试图为所有函数推广这些函数采用相同的模板参数,但函数参数不同,因此需要以某种方式传递函数指针数组。在等号的右侧是函数模板实例化。需要为此部分传入特定的函数模板,但我发现如果不使用仿函数,则无法将未实例化的模板化函数作为模板参数传递。

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

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

1 个答案:

答案 0 :(得分: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