Вариант с кандидатами в Variadic не имеет аналогов - PullRequest
1 голос
/ 12 февраля 2012

Я пытаюсь собрать универсальный метод вызова (для моста C ++ OO / v8), используя метапрограммирование вариационных шаблонов для построения списка параметров, преобразования в нативные типы и, наконец, выполнения присоединенного метода после получения входящего параметра.список пуст (и поэтому создается исходящий текст):

template<typename... PARAMS>
class InvocationBuilder {
public:

void invoke(const Arguments &source, PARAMS&... params) {
    cout << "Invoke" << endl;
    (instance->*(method))(*params...);
}

template<class HEAD, class ... TAIL>
void invoke(const Arguments &source, PARAMS... params) {
    cout << "Expand" << endl;
    Type<HEAD> param(source[sizeof...(PARAMS)]);
    InvocationBuilder<PARAMS..., HEAD> builder;
    builder.template invoke<TAIL...>(source, params..., *param);
}

Класс Type является просто оболочкой для создания стековых вариантов параметров v8 (так что, например, строки char * можно использовать, пока вобласть действия во время вызова, но автоматически очищается после возврата вызова).

Теперь, когда фактический мост вызывает это, со списком параметров, используя:

InvocationBuilder<> builder;
builder.template invoke<ARGS...>(args);

Где аргументыявляется ссылкой v8 :: Arguments.

Компилятор корректно объединяет в цепочку каждый шаг генерации параметра, но не соответствует не шаблонному методу invoke (), чтобы фактически выполнить собственный метод C ++.

Сообщение об ошибке выглядит следующим образом:

include/link/function.hh: In member function 'void sjs::link::InstanceFunctionVariadic<CLASS, ARGS>::InvocationBuilder<PARAMS>::invoke(const v8::Arguments&, PARAMS ...) [with HEAD = int, TAIL = {}, PARAMS = {int, int}, CLASS = SomeClass, ARGS = {int, int, int}]':
include/link/function.hh:65:6:   recursively instantiated from 'void sjs::link::InstanceFunctionVariadic<CLASS, ARGS>::InvocationBuilder<PARAMS>::invoke(const v8::Arguments&, PARAMS ...) [with HEAD = int, TAIL = {int}, PARAMS = {int}, CLASS = SomeClass, ARGS = {int, int, int}]'
include/link/function.hh:65:6:   instantiated from 'void sjs::link::InstanceFunctionVariadic<CLASS, ARGS>::InvocationBuilder<PARAMS>::invoke(const v8::Arguments&, PARAMS ...) [with HEAD = int, TAIL = {int, int}, PARAMS = {}, CLASS = SomeClass, ARGS = {int, int, int}]'
include/link/function.hh:47:5:   instantiated from 'v8::Handle<v8::Value> sjs::link::InstanceFunctionVariadic<CLASS, ARGS>::run(const v8::Arguments&) [with CLASS = SomeClass, ARGS = {int, int, int}]'
test.cc:41:1:   instantiated from here
include/link/function.hh:65:6: error: no matching function for call to 'sjs::link::InstanceFunctionVariadic<SomeClass, int, int, int>::InvocationBuilder<int, int, int>::invoke(const v8::Arguments&, int&, int&, int)'
include/link/function.hh:65:6: note: candidate is:
include/link/function.hh:61:10: note: template<class HEAD, class ... TAIL> void sjs::link::InstanceFunctionVariadic<CLASS, ARGS>::InvocationBuilder::invoke(const v8::Arguments&, PARAMS ...) [with HEAD = HEAD, TAIL = {TAIL ...}, PARAMS = {int, int, int}, CLASS = SomeClass, ARGS = {int, int, int}]

Сообщение ясно показывает, что первые три шага, дляМетод void test экземпляра C ++ (int a, int b, int c) работает правильно, извлекает параметры с помощью Type и передает результаты, но я не могу понять, почему последний invoke () не используется правильно.

Я пытался полностью его специализовать, но затем я получаю сообщения об ошибках по поводу специализации вне области пространства имен (что, как я полагаю, связано с тем, что метод является членом шаблонного класса).

Я также попытался сместить списки входящих / исходящих параметров, чтобы входящий входил в шаблон переменной класса, а исходящий - в метод, чтобы вместо этого специализировать класс для вызова - но я сталкиваюсь с сообщением «извините, не реализовано» ораспаковка variadic в статический шаблон.

Я также пытался обойти это, используя общий шаблон с одним variadic, затем специализируясь на случае HEAD / TAIL и специализируясь на случае пустого набора, но затем яполучить немедленную неоднозначность (вероятно, потому что значения HEAD / TAIL на самом деле не роцениваю как параметры - просто в шаблоне).

Но пока без кубиков.У кого-нибудь есть другие идеи, или можете объяснить, где я ошибаюсь?

1 Ответ

1 голос
/ 12 февраля 2012

Обратите внимание:

  • вы явно пытаетесь вызвать шаблон
  • ваш шаблон invoke всегда требует, чтобы PARAMS... передавалось как аргументы функции

Одна из возможных альтернатив:

#include <functional>

template<class... Types> struct List {};

template<class... PARAMS> struct Invoker {
    typedef std::function<void (PARAMS&...)> Fn;
    Fn fn_;    
    Invoker(const Fn&& fn) : fn_(fn) {}

    void invoke(List<>, PARAMS&... params) {
        fn_(params...);
    }

    template<class HEAD, class... TAIL, class... ARGS>
    void invoke(List<HEAD, TAIL...>, ARGS... params) {
        HEAD param; // or your Type<HEAD> ... etc.
        invoke(List<TAIL...>(), params..., param);
    }
};

void f(int, int, int) {} // some function you want to call

int main() {
    Invoker<int,int,int> inv(&f);
    inv.invoke(List<int,int,int>());
}

... без небольшого скомпилируемого примера вашего варианта использования (с фиктивными типами и т. Д.) Было бы немного трудоемким, чтобы сделать это более близким к вашему коду.

...