Аргумент Boost bind placeholder равен количеству аргументов шаблона Variadic

Я хочу знать, можно ли использовать количество аргументов, переданных в переменный шаблон, в качестве заполнителя в вызове 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

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

Спасибо

Ответ 1

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

Ответ 2

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

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) {}
};

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

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