Аргумент 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, предоставит вам возможность достичь вашей первоначальной цели.