可变参数模板的模拟

时间:2013-08-21 09:09:43

标签: c++ templates variadic-templates

我正在为我们的API编写一个小包装器,但我遇到了一个问题。 来自外部客户端(JavaScript引擎)的每个调用都是来自ApiBase的名为execute的调用函数,所有参数都作为std :: string传递,没有在api调用中传递的内容,每个值都转换为字符串。

我的想法是使用指向成员函数的指针,并尝试将那些传递的字符串转换为编写特定函数的程序员需要的C ++类型。

例如:

struct MyApiForVeryImportantDevice{
void Init(int, int);
};

MyApiForVeryImportantDevice api_entry;
ApiBase* api = make_api(&api_entry, &MyApiForVeryImportantDevice::Init);

//serve api

代码api->execute("1", "2", "", "")中的Somwhere被4个10字符串参数(总是4或10)调用,没有多少参数在api调用中传递(不要问我为什么......)。

我知道这可以使用可变参数模板完成,但不幸的是我不能在这个项目中使用它。 我的解决方案基于“模拟可变参数模板”,但它只是丑陋。为了支持10个参数,我需要编写10个类ApiCall和10个make_api函数,这很容易出错,你还有其他想法吗?某种mpl(也许是类型列表?)? 下面给出的代码只是2和10个参数的示例,我需要0-10个参数。

问候。

template<class T>
T convert(const string& v){
    return T();
}

template<>
int convert(const string& v)
{
    return boost::lexical_cast<int>(v);
}


template<class T, class R, class A0, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
class ApiCall : public ApiBase
{
    typedef T result_type;
    typedef R class_type;
    typedef boost::function<result_type(class_type*,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9)> functor_type;

    ApiCall(T* obj, functor_type f)
    {
        func = boost::bind(f, _1, obj);
    }

    virtual void execute(const string& param1, const string& param2, const string& param3, const string& param4)
    {   
        func(convert<A0>(param0), convert<A1>(param1), convert<A2>(param2), convert<A3>(param3), convert<A4>(param4));
    }

    virtual void execute(const string& param0, const string& param1, const string& param2, const string& param3,
                         const string& param4, const string& param5, const string& param6, const string& param7
                         const string& param8, const string& param9)
    {       
        func(convert<A0>(param0), convert<A1>(param1), convert<A2>(param2), convert<A3>(param3), convert<A4>(param4), convert<A5>(param5), 
                     convert<A6>(param6),convert<A7>(param7), convert<A8>(param8), convert<A9>(param9));
    }

private:
    functor_type func;
};

template<class T, class R, class A0, class A1>
class ApiCall : public ApiBase
{
    typedef R result_type;
    typedef T class_type;
    typedef boost::function<result_type(class_type*,A0, A1)> functor_type;

    ApiCall(T* obj, functor_type f)
    {
        func = boost::bind(f, _1, obj);
    }

    virtual void execute(const string& param1, const string& param2, const string& param3, const string& param4)
    {   
        func(convert<A0>(param0), convert<A1>(param1));
    }

    virtual void execute(const string& param0, const string& param1, const string& param2, const string& param3,
                         const string& param4, const string& param5, const string& param6, const string& param7
                         const string& param8, const string& param9)
    {       
        func(convert<A0>(param0), convert<A1>(param1));
    }

private:
    functor_type func;
};

template<class T, class R, class A0, class A1>
ApiCall<T, R, A0, A1>* make_api(T obj, R(T::*fun)(A0, A1))
{
    return new ApiCall<T,R,A0,A!>(obj, fun);
}

template<class T, class R, class A0, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
ApiCall<T,R,A0,A1,A2,A3,A4,A5,A6,A7,A8, A9>* make_api(T obj, R(T::*fun)(A0))
{
    return new ApiCall<T,R,A0,A1,A2,A3,A4,A5,A6,A7,A8,A9>(obj, fun);
}

1 个答案:

答案 0 :(得分:1)

我认为 类型列表 可以在这里用来模拟可变参数模板。

类型列表是一种模板元编程构造,充当类型的已知列表。由Andrei Alexandrescu在他的书"Modern C++ design"中介绍 基本上,类型列表是这样的类:

template<typename HEAD , typename TAIL>
struct type_list
{
    typedef HEAD head;
    typedef TAIL tail;
};

可以用作下面的内容:

//A typelist wich stores int, bool, and char:
typedef type_list<int,type_list<bool,type_list<char, nil>>> list;  

nil是一种用作标记列表末尾的标记的类型。 我们可以使用C宏来定义快捷方式,使类型列表定义变得容易:

#define MAKE_TYPELIST_1( type_1 ) type_list<type_1,nil>
#define MAKE_TYPELIST_2( type_1 , type_2 ) type_list<type_1,MAKE_TYPELIST_1( type_2 )>
#define MAKE_TYPELIST_3( type_1 , type_2 , type_3 ) type_list<type_1,MAKE_TYPELIST_2( type_2 , type_3 )>

......等等。

您可以使用此构造来传递参数类型,而不使用可变参数模板:

template<typename T , typename R , typename ARGS_LIST>
class APICall ...

typedef APICall<...,MAKE_TYPELIST_3(std::string,std::string,std::string)> tree_strings_call;

我建议您查看Modern C ++设计的第三章。有关于类型列表,其操作(index_of,type_at等)的完整说明,以及它的使用的良好示例。