可变参数模板和标准::绑定

Variadic templates and std::bind

本文关键字:标准 绑定 变参 参数      更新时间:2023-10-16

给定以下模板化函数,如何更改它以利用可变参数模板? 也就是说,用可变参数代替 P1 和 P2 替换 std::bind 占位符? 目前,我每个 arity 都有一个这些函数,arity zero 没有 P 参数,直到 arity 9 有 P1 到 P9 参数。 如果可能的话,我希望将其折叠为单个函数。

template<typename R, typename T, typename U, typename P1, typename P2>
void Attach(R (T::*f)(P1, P2), U p)
{
    AttachInternal(p, std::bind(f, 
                                p.get(), 
                                std::placeholders::_1, 
                                std::placeholders::_2));
}

您可以(部分)专精std::is_placeholder自定义模板的专化。这样,您可以通过通常的int_sequence技术引入占位符生成器。

来自 [func.bind.isplace]/2

实现应提供具有BaseCharacteristic integral_constant<int, J> 如果Tstd::placeholders::_J的类型,否则它的BaseCharacteristic应为integral_constant<int, 0>。程序可以将此模板专用于用户定义的类型,T具有integral_constant<int, N> BaseCharacteristic,并N > 0指示应将T视为占位符类型。

通常int_sequence

#include <cstddef>
template<int...> struct int_sequence {};
template<int N, int... Is> struct make_int_sequence
    : make_int_sequence<N-1, N-1, Is...> {};
template<int... Is> struct make_int_sequence<0, Is...>
    : int_sequence<Is...> {};

自定义占位符模板和is_placeholder的专用化:

template<int> // begin with 0 here!
struct placeholder_template
{};
#include <functional>
#include <type_traits>
namespace std
{
    template<int N>
    struct is_placeholder< placeholder_template<N> >
        : integral_constant<int, N+1> // the one is important
    {};
}

我不知道在哪里介绍1;我考虑的地方都不是最佳的。

使用它来编写一些活页夹:

template<class Ret, class... Args, int... Is>
void my_bind(Ret (*p)(Args...), int_sequence<Is...>)
{
    auto x = std::bind(p, placeholder_template<Is>{}...);
    x( Args(42)... );
}
template<class Ret, class... Args>
void my_bind(Ret (*p)(Args...))
{
    my_bind(p, make_int_sequence< sizeof...(Args) >{});
}

活页夹的使用示例:

#include <iostream>
void foo(double, char, int) { std::cout << __PRETTY_FUNCTION__ << "n"; }
void bar(bool, short) { std::cout << __PRETTY_FUNCTION__ << "n"; }
int main()
{
    my_bind(foo);
    my_bind(bar);
}
我想

提出一个更简单的解决方案,将成员函数绑定到可变数量的占位符:

template<typename R, typename T, typename U, typename... Args>
std::function<R(Args...)> Attach(R (T::*f)(Args...), U p)
{
    return [p,f](Args... args)->R { return (p->*f)(args...); };
};

一个简单的用法示例如下所示

class CrazyAdd
{
public:
    CrazyAdd(double val)
    : m_crazyPart(val)
    {}
    double add(double a, double b)
    {
        return a+b+m_crazyPart;
    }
private:
    double m_crazyPart;
};
void main() {
    CrazyAdd myAdd(39);
    // Create a function object that is bound to myAdd
    auto f = Attach(&CrazyAdd::add, &myAdd);
    // Call the function with the parameters    
    std::cout << f(1,2) << std::endl;   // outputs 42
}

就我个人而言,我认为这是Scott Meyer推荐lambdas而不是std::bind的另一个很好的例子。