如何实现一个自动插入隐含占位符的easy_bind()?

kfm*_*e04 7 c++ templates variadic-templates c++11

我最近在网上找到了这个漂亮的片段 - 它允许你绑定而不必传递明确的占位符:

template <typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> 
easy_bind(ReturnType(*MemPtr)(Args...))
{
  return [=]( Args... args ) -> ReturnType { return (*MemPtr)( args... ); };
}
Run Code Online (Sandbox Code Playgroud)

这个版本很好用没有args:

auto f1 = easy_bind( (std::string(*)(A&,A&))&Worker::MyFn );
Run Code Online (Sandbox Code Playgroud)

后来调用:

std::string s = f1( *p_a1, *p_a2 );
Run Code Online (Sandbox Code Playgroud)

是否可以修改代码以使用最多n个args,用占位符填充2-n(在本例中)?例如,这个应该有一个占位符:

auto f2 = easy_bind( (std::string(*)(A&,A&))&Worker::MyFn, *p_a1 );     
Run Code Online (Sandbox Code Playgroud)

后来调用:

std::string s = f2( *p_a2 );
Run Code Online (Sandbox Code Playgroud)

奖金

最终,有这样的东西很好(它不会插入任何占位符,因为它会消耗掉最后一个占位符),但我不认为它对这个实现是可行的(我认为不能模式匹配签名):

auto f3 = easy_bind( f2, *p_a2 );     
Run Code Online (Sandbox Code Playgroud)

后来调用:

std::string s = f3();
Run Code Online (Sandbox Code Playgroud)

最重要的是,拥有一个我不需要放在占位符中的bind版本会很好 - 这在通用TMP代码中非常有用.

Xeo*_*Xeo 15

使用索引技巧告诉std::bind您自己的占位符类型的能力,这是我想出的:

#include <functional>
#include <type_traits>
#include <utility>

template<int I> struct placeholder{};

namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::

namespace detail{
template<std::size_t... Is, class F, class... Args>
auto easy_bind(indices<Is...>, F const& f, Args&&... args)
  -> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...))
{
    return std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...);
}
} // detail::

template<class R, class... FArgs, class... Args>
auto easy_bind(std::function<R(FArgs...)> const& f, Args&&... args)
    -> decltype(detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...))
{
    return detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

实例.

请注意,我要求函数参数为easy_bind类型std::function或可转换为它,以便我有一个明确的签名可用.

  • "实例"链接已经死亡.你能举例说明用法吗? (5认同)
  • @ kfmfe04:是的,`detail`只不过是实现细节的约定.`std`中的代码可以使`std :: bind`知道我们的占位符. (2认同)