Пример Boopre's Interpreter.hpp с функциями-членами класса - PullRequest
4 голосов
/ 05 декабря 2009

Boost поставляется с файлом примера в

boost_1_41_0\libs\function_types\example

называется interpreter.hpp и interpreter_example.hpp

Я пытаюсь создать ситуацию, когда у меня есть набор функций с различными аргументами, типами возвращаемых данных и т. Д., Которые регистрируются и записываются в одном месте. Затем получите возможность извлечь функцию и выполнить ее с некоторыми параметрами.

Прочитав несколько вопросов здесь и из нескольких других источников, я думаю, что дизайн, реализованный в этом файле примера, настолько хорош, насколько я смогу получить. Она принимает функцию любого типа и позволяет вам вызывать ее, используя список строковых аргументов, который разбирается в нужные типы данных. В основном это консольный интерпретатор команд, и это, вероятно, то, что он хотел проиллюстрировать.

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

В примере вы увидите

interpreter.register_function("echo", & echo);
interpreter.register_function("add", & add);
interpreter.register_function("repeat", & repeat);

Я хочу сделать что-то вроде

test x;
interpreter.register_function("classFunc", boost::bind( &test::classFunc, &x ) );

Но это нарушает любое количество аргументов. Так что я думаю, что какой-то вариант автоматического генерирования boost :: bind (& test :: classFunc, & x, _1, _2, _3 ...) был бы подходом, я просто не уверен, как лучше его реализовать.

Спасибо

Ответы [ 3 ]

7 голосов
/ 03 августа 2010

Я работал над этой проблемой, и мне несколько удалось заставить интерпретатор наддува принять функцию-член, такую ​​как:

// Registers a function with the interpreter, 
// will not compile if it's a member function.
template<typename Function>
typename boost::enable_if< ft::is_nonmember_callable_builtin<Function> >::type
register_function(std::string const& name, Function f);

// Registers a member function with the interpreter. 
// Will not compile if it's a non-member function.
template<typename Function, typename TheClass>
typename boost::enable_if< ft::is_member_function_pointer<Function> >::type
register_function(std::string const& name, Function f, TheClass* theclass);

Оператор enable_if используется для предотвращения использования неправильного метода во время компиляции. Теперь, что вам нужно понять:

  • Он использует boost :: mpl для анализа типов параметров аргумента вызываемой функции (которая в основном является указателем на функцию)
  • Затем подготавливает вектор слияния во время компиляции (это вектор, который может хранить различные объекты разных типов одновременно)
  • Когда mpl завершит синтаксический анализ всех аргументов, метод apply "parsing" превратится в метод apply "invoke", следуя шаблонам.
  • Основная проблема заключается в том, что первый аргумент встроенной функции вызываемого члена - это объект, который содержит вызываемый метод.
  • Насколько мне известно, mpl не может анализировать аргументы чего-то другого, кроме вызываемой встроенной функции (т. Е. Результата Boost :: Bind)

Итак, что нужно сделать, это просто добавить один шаг к «разбору» применения, то есть добавить соответствующий объект в цикл применения! Вот оно:

template<typename Function, typename ClassT>
typename boost::enable_if< ft::is_member_function_pointer<Function> >::type
interpreter::register_function( std::string const& name, 
                                Function f, 
                                ClassT* theclass);
{   
    typedef invoker<Function> invoker;
    // instantiate and store the invoker by name
    map_invokers[name] 
            = boost::bind(&invoker::template apply_object<fusion::nil,ClassT>
                          ,f,theclass,_1,fusion::nil());
}

в переводчике :: invoker

template<typename Args, typename TheClass>
static inline
void 
apply_object( Function func, 
              TheClass* theclass, 
              parameters_parser & parser, 
              Args const & args)
{
    typedef typename mpl::next<From>::type next_iter_type;
    typedef interpreter::invoker<Function, next_iter_type, To> invoker;

    invoker::apply( func, parser, fusion::push_back(args, theclass) );      
}

Таким образом, он просто пропустит первый тип аргумента и проанализирует все правильно. Метод можно назвать так: invoker.register_function("SomeMethod",&TheClass::TheMethod,&my_object);

1 голос
/ 05 декабря 2009

Я не в фьюжн и поэтому не вижу, как это исправить простым и элегантным способом (я в основном не понимаю, как должны работать функции-члены), но я работал над чем-то похожим это может быть альтернативой для вас.
Если вы хотите посмотреть на результат, он находится в репозитории Firebreath .

Короче говоря:

  • MethodConverter.h содержит основные функции
  • уродливый dispatch_gen.py генерирует этот заголовок
  • ConverterUtils.h содержит функциональные возможности утилиты, такие как преобразование в целевые типы
  • TestJSAPIAuto.h и jsapiauto_test.h содержат модульный тест, который показывает его в действии

Основные изменения, вероятно, будут связаны с удалением специфичных для FB типов, токенизацией входной последовательности перед вызовом функторов и предоставлением ваших собственных функций преобразования.

0 голосов
/ 05 декабря 2009

Один из вариантов - сделать набор шаблонов

template <class T, class Ret>
void register_function(const char *name, Ret (T::*fn)()) { /* boost::bind or your way to register here */ }

template <class T, class Ret, class Arg1>
void register_function(const char *name, Ret (T::*fn)(Arg1)) { /*...*/ )

И так далее. До тех пор, пока C ++ 0x не выйдет с различными шаблонами, вы можете использовать Boost.Preprocessor для генерации необходимого количества шаблонов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...