Variadic模板和std :: bind

时间:2014-01-17 17:56:13

标签: c++ templates

鉴于以下模板化功能,如何更改它以利用可变参数模板?也就是说,用一个可变参数而不是P1和P2替换std :: bind占位符?目前我每个arity都有这些函数之一,arity为零,没有P参数,直到具有P1到P9参数的arity 9。如果可能的话,我希望将其合并为一个功能。

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

2 个答案:

答案 0 :(得分:19)

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

来自[func.bind.isplace] / 2

  

实施应提供BaseCharacteristic integral_constant<int, J>的定义   如果Tstd::placeholders::_J的类型,则其BaseCharacteristic integral_constant<int, 0>。程序可以为此模板专门为用户定义的类型T提供BaseCharacteristic integral_constant<int, N> 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);
}

答案 1 :(得分:1)

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

XrmServiceToolkit.Soap.setState(entityName,targetEntity, "0", "0",false);

用法的一个简单示例如下

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

我个人认为这是Scott Meyer建议使用lambda而不是std :: bind的另一个很好的例子。