Повысить аргумент-заполнитель привязки, равный количеству аргументов шаблона Variadic - PullRequest
10 голосов
/ 09 ноября 2011

Я хочу знать, возможно ли использовать количество аргументов, передаваемых в шаблон переменной, в качестве заполнителя при вызове boost :: bind.

Примерно так:

template <typename ... Args>

boost::bind(&function, this, anArg, _1));         //If Args count equals 1
boost::bind(&function, this, anArg, _1, _2));     //If Args count equals 2
boost::bind(&function, this, anArg, _1, _2, _3)); //If Args count equals 3

Возможно ли это?

Спасибо

Ответы [ 4 ]

1 голос
/ 23 января 2013

Определенно есть способ частичной специализации. Ваш вариадик сразу не знает количество аргументов? Вы должны использовать рекурсию во время компиляции, в течение этого времени вы можете составлять свои аргументы, используя boost :: mpl (или считать их, используя простое приращение интегральной константы). затем в последнем невариантном рекурсивном вызове (с 0 аргументами) вы вызываете mpl :: size для своего контейнера (или просто используете встроенный счетчик, если вы выбрали этот способ) для вызова Callable, как и другой ответ, который содержит все аргументы , плюс один целочисленный параметр шаблона в начале списка типов. и это то, что вы специализируетесь. Вы делаете вызывающую сторону для каждого числа аргументов, которые будут вызывать правильную привязку в соответствии с ее специализированным числом аргументов. (Структуры Callable (частично) специализируются в соответствии с параметром шаблона целого числа аргументов. И хотя функция Call принимает максимальное количество аргументов, она только оборачивает правильный вызов boost :: bind, например, bind (.., _1, _2) для Callable <2, T1, T2, T3>) это не страшно, но я подтверждаю, что я использовал этот подход в C ++ 03 в прошлом.

0 голосов
/ 20 февраля 2014

Использование _1, _2, ... напрямую невозможно с помощью шаблона с переменным числом аргументов. Вместо этого вам нужно использовать расширенные макросы.

Однако вы можете обернуть эти заполнители в шаблонную фабрику, чтобы получить _1 с аргументом шаблона 1, _2 для 2 и т. Д. *

Реализации, такие как gcc / msvc, уже определяют заполнители как шаблонную структуру (соответственно std :: _ Placeholder и std :: _ Ph), поэтому вы можете определить свою фабрику следующим образом:

struct ph_factory {
    template<size_t holder>
    static std::_Placeholder<holder> make_ph() {
        return std::_Placeholder<holder>();
    }
};

Это определено, вы можете расширить пакет параметров со всеми необходимыми заполнителями:

struct tester {

    template<size_t ... holders>
    void test(int val) {
        auto callable = std::bind(&tester::call, this, val, ph_factory::make_ph<holders>()...);
        callable('a', 42, 'c');
    }

    void call(int v1, char c1, int v2, char c2) {
        cout << "calling :" << v1 << " " << c1 << " " << v2 << " " << c2 << endl;
    }
};

Таким образом, следующий код выведет «call: 10 c 42 a»

int main() {
    tester t;
    t.test<3,2,1>(10);
}

Использование таких трюков, как make_indice, даст вам возможность достичь вашей первоначальной цели.

0 голосов
/ 20 июля 2013

Это не ответ на конкретную проблему, а хороший обходной путь для проблемы, которую вы, вероятно, пытаетесь решить.

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

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(), CALLBACK_TARGET_CLASS* callbackTarget)
{
    return std::bind(memberFunction, callbackTarget);
}

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0), CALLBACK_TARGET_CLASS* callbackTarget)
{
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1);
}

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0, typename P1>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0, P1), CALLBACK_TARGET_CLASS* callbackTarget)
{
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1, std::placeholders::_2);
}



template<typename RETURNTYPE, typename... ARGS>
struct Delegate
{
    std::function<RETURN_TYPE (ARGS...)> callbackFunction;

    template<class CALLBACK_TARGET_CLASS>
    void Bind(CALLBACK_TARGET_CLASS* callbackTarget, RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(ARGS...))
    {
        callbackFunction = BindFunction<CALLBACK_TARGET_CLASS, RETURN_TYPE, ARGS...>(memberFunction, callbackTarget); 
    }

    void Callback(ARGS... params)
    {
        callbackFunction(params...);
    }
};

Использование делает нас похожими на это ..

class Foo
{
public:
    void Bar(int x);
}

Foo foo;
Delegate<void, int> myDelegate;

myDelegate.Bind(&foo, &Foo::Bar);

myDelegate.Callback(3);
0 голосов
/ 18 ноября 2011

Может быть, вы должны объяснить, что вы хотите сделать, немного подробнее.Если вы просто ищете решение для обработки трех разных подписей, которые различаются по типам параметров, вы можете сделать что-то вроде этого:

template<typename signature>
struct callable;

template<typename P0, typename P1, typename P2>
struct callable<void (P0, P1, P2)>
{
    void bind()
    {
        boost::bind(&callable::operator(), this, _1, _2, _3);
    }

    void operator()(P0, P1, P2) {}
};
...