Boost绑定占位符参数等于Variadic Template参数的数量

时间:2011-11-09 01:01:09

标签: c++ templates boost bind variadic-templates

我想知道是否可以在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 个答案:

答案 0 :(得分:1)

肯定有一种部分专业化的方法。 你的可变参数不知道正确的参数数量对吗?你必须使用编译时递归,在这段时间你可以使用boost :: mpl堆栈你的参数(或者使用简单的整数常量增量来计算它们)。 然后在你的最后一个非变量递归调用(使用0 arg)你在容器上调用mpl :: size(或者如果你选择那样只使用积分计数器)来调用Callable,就像另一个回答一样,它包含所有的参数,在类型列表的开头加一个整数模板参数。这就是你的专长。你根据其特定的参数数量为每个将调用正确绑定的参数创建一个调用者。 (Callable结构根据参数整数模板参数的数量(部分)专门化。即使Call函数采用参数的最大数量,它只包装正确的boost :: bind调用,例如bind(.., _1,_2)表示可调用&lt; 2,T1,T2,T3&gt;) 它并不可怕,但我确认我过去在C ++ 03中使用过这种方法。

答案 1 :(得分:0)

也许你应该更详细地解释一下你想做什么。如果你只是在寻找一个解决方案来处理三个不同的签名,这些签名因参数类型而不同,你可以这样做:

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

答案 2 :(得分:0)

这不是特定问题的答案,而是您可能尝试解决的问题的一个很好的解决方法。

在实现通用委托机制时遇到了同样的问题。我的解决方案是在绑定调用之上使用包装器,专门针对变体进行调整。虽然它没有解决问题,但它确实将冗余代码最小化到仅仅绑定调用,最重要的是给了我一个基于可变参数的委托系统,我可以在任何地方使用。

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

答案 3 :(得分:0)

使用可变参数模板无法直接使用_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;
    }
};

所以下面的代码将输出“calling:10 c 42 a”

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

使用像make_indice这样的技巧会让你有可能达到原来的目标。