10

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

4 回答 4

1

肯定有一种部分专业化的方法。你的变量不知道参数的数量吗?您必须使用编译时递归,在此期间您可以使用 boost::mpl 堆叠您的参数(或使用简单的整数常量增量对它们进行计数)。然后在您最后一次非可变递归调用(使用 0 arg)中,您在容器上调用 mpl::size(或者如果您选择这种方式,则只使用积分计数器)来调用 Callable 像其他答案一样,它包含所有参数, 在类型列表的开头加上一个完整的模板参数。这就是你的专长。您为每个数量的参数创建一个调用者,该调用者将根据其专用数量的参数调用正确的绑定。

于 2013-01-23T09:22:06.557 回答
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) {}
};
于 2011-11-17T20:07:43.307 回答
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);
于 2013-07-20T16:57:09.593 回答
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 之类的技巧将使您有可能实现最初的目标。

于 2014-02-20T12:54:46.670 回答