2013-08-21 2 views
1

Я пишу небольшую оболочку для нашего API, и я столкнулся с проблемой. Каждый вызов от внешнего клиента (механизм JavaScript) выполняется при вызове функции из ApiBase с именем execute, все параметры передаются как std :: string, no mather, что было передано в вызове api, каждое значение преобразуется в строку.Моделирование вариационных шаблонов

Моя идея - использовать функцию-указатель-член и попытаться преобразовать прошедшую строку в типы C++, которые требуется программисту, который пишет определенную функцию.

Например:

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

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

//serve api 

Somwhere в коде api->execute("1", "2", "", "") вызывается с 4 O 10 параметров строки (всегда 4 или 10), не Mather сколько параметров, где проходил в апи вызова (не спрашивайте меня, почему ...).

Я знаю, что это можно сделать с помощью вариативных шаблонов, но, к сожалению, я не могу использовать его в этом проекте. Мое решение основано на «моделировании вариативных шаблонов», но это просто уродливо. Чтобы поддерживать 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

Знаете ли вы, что искали? См. Здесь: http://stackoverflow.com/questions/901907/how-to-use-typelists – LukeCodeBaker

ответ

1

Я думаю, что списки типов можно использовать здесь, чтобы имитировать VARIADIC шаблоны.

Typelists - это шаблонная метапрограммируемая конструкция, которая действует как список типов. Был представлен Андреем Александреску в его книге "Modern C++ design".
В основном TypeList класс, как это:

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 макросов для определения ярлыков, чтобы сделать определения TypeList легко:

#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; 

Я предлагаю вам оформить главу три дизайна современных C++. Существует полное объяснение списков типов, его операций (index_of, type_at и т. Д.) И хороших примеров его использования.

+0

Я пытаюсь использовать typelist, чтобы получить его работу, но как я храню функтор (указатель-на-член-funtcion) с произвольным числом параметров для дальнейшего вызова? – sop3k

Смежные вопросы