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

Это возможно?

Спасибо


person Blizter    schedule 09.11.2011    source источник
comment
Здесь есть хорошая реализация утилиты make_indice: http://preney.ca, но мне трудно понять, как я могу использовать его с boost::arg‹›   -  person Blizter    schedule 09.11.2011
comment
Эта ссылка была отлично прочитана, и функция apply( Func, std::tuple ) может когда-нибудь пригодиться.   -  person deft_code    schedule 11.11.2011
comment
Я вижу typename... Args. Вы используете С++ 11?   -  person kennytm    schedule 18.11.2011


Ответы (4)


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

person Lightness1024    schedule 23.01.2013

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

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) {}
};
person 0xbadf00d    schedule 17.11.2011

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

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

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);
person Shammi    schedule 20.07.2013

Использование _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;
    }
};

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

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

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

person Kiwi    schedule 20.02.2014
comment
Никогда не полагайтесь на _Names, они полностью закрыты для реализации, и у вас нет причин даже думать о них. Есть лучшие способы, один из которых заключается в том, что вы помещаете все заполнители в tuple и get<I> их с расширением пакета. Другой заключается в том, что вы регистрируете свой собственный заполнитель (по этой причине стандарт предоставляет черту is_placeholder, которую вы можете специализировать. - person Xeo; 20.02.2014