【发布时间】:2015-03-21 05:27:53
【问题描述】:
我需要一个 bind 函数,它的行为类似于 std::bind,但返回 std::function 的适当特化。
我认为std::function 模板参数可以使用函数参数中的占位符编号提取。不过,这看起来并不那么微不足道。是否有任何可用的实现?
为什么我需要这个
我想实现一个语义类似于this JavaScript one的waterfall函数。
这是我想象的 C++ 中的样子:
std::function<void(const std::string &)> f = waterfall(
[]( const std::function<void(int)> &cb, const std::string & ) {
...;
cb( 1 );
},
[]( const std::function<void(double, double)> &cb, int ) {
...;
cb(0.5, 10);
},
[]( double, double ) {
}
);
换句话说,waterfall 将采用一堆函数,每个函数(但最后一个)将一个函数作为第一个参数。 waterfall 会将每个函数绑定到前一个函数(当然是从最后一个函数开始),并返回一个函数。
瀑布基本上应该是这样的:
// recursion termination: `waterfall` called with a single functions
template< typename Arg >
auto waterfall( const Arg& first ) -> decltype( first ) {
return first;
}
// recursion: `waterfall` called with mulitple functions
template< typename Arg, typename... Args >
... waterfall( const Arg& first, Args... args ) {
return std::bind( first, waterfall(std::forward<Args>(args)...) );
}
虽然存在三个未解决的问题:
- 在使用多个参数调用时确定
waterfall的返回类型。它不能是decltype( std::bind(first, waterfall(...)) )(因为 C++ 不允许递归调用模板函数来推断其类型)。如果我知道函数的类型(即Arg),那么如果没有第一个参数,那将是我正在寻找的返回类型。 - 我想我需要知道
first的参数数量才能正确std::bind。 -
std::bind的返回类型不符合我的要求:嵌套std::bind调用合并所有绑定函数在一起,而不是组合它们。
我能够通过编写一个 std::bind 包装器来绕过第三点,该包装器将绑定函数包装到 T 类型的对象中,这样 std::is_bind_expression<T>::value == false。
对于前两点,我需要找出waterfall 参数的返回类型和参数类型。如果函数是std::functions,这将是微不足道的。如果它们是 lambda、经典函数或具有单个 operator() 的函子,那也很简单:我只需要使用类似 this function_traits 的东西。但是我真的想将使用std::bind 绑定的函数传递给waterfall,而不必手动将它们转换为std::functions,因为这使我的代码方式 更短,方式更清晰,waterfalls 大。
有什么想法、想法或建议吗?
【问题讨论】:
-
在 C++11 中,您应该更喜欢使用 lambda 表达式而不是
std::bind和朋友。你能举个例子来说明你想做的事吗?请注意,lambda 闭包可以隐式转换为std::functions。 -
您能解释一下您打算如何使用它吗?为什么你认为你需要它?通常,您无法推断出函数调用对象的唯一签名,更不用说绑定了一些参数的对象了。对象的消费者几乎总是知道它将如何调用该对象,因此应该是确定擦除类型的人,而不是可调用对象的提供者。最常见的半有效原因是您正在编写远程调用协议(来自不同的内存空间或不同的语言),即使在那里协议接口也应该确定签名!
-
这里有一个答案stackoverflow.com/a/21788988/683218 (by dyp) 关于如何返回一个不允许多余参数的类绑定对象的问题。我不知道它是否相关,或者您是否可以调整它以返回 std::function 对象。
-
@LightnessRacesinOrbit:你是对的。我是否应该删除这个问题,并打开一个新问题来询问我的最终目标(即实现
waterfall的事情? -
@peoro: 可能是明智的:)