std::bind
有时被描述为“部分申请”。当函数的所有参数都绑定时,函数本身没有被应用的任何原因?
例如,以下代码不打印任何内容。
#include <functional>
#include <iostream>
using namespace std;
using namespace std::placeholders;
void f(int a,string b) {cout << a << b << endl;};
int main() {
bind(bind(f,1,_1),"Hi!");
return 0;
}
有没有办法编写一个绑定变量,可以在修复所有参数后应用该函数?
- 更新 -
我现在从答复中了解到std::bind
并非完全是部分申请。所以,在问题的第二部分,我怎样才能编写类似std :: bind的东西,但是可以部分应用。
我知道bind(bind(f,1,_1),"Hi!")()
将调用最终的0-ary函数并返回结果值(在示例中打印1Hi
)。是否可以进行模板编程以在bind的终端情况下调用函数调用operator()?
换句话说,是否可以编写函数bind1
:
template< class R, class F, class... Args >
bind1( F f, Args... args )
,这样当std::is_placeholder<T>::value == 0
的每个成员args
时,
bind1()
除了std::bind()
之外,还可以调用operator()?
答案 0 :(得分:2)
没有参数的函数只是Haskell中的一个值。你不打电话,你只是使用它。由于没有副作用,因此没有可观察到的差异。
在OCaml中,根本没有无参数函数,需要添加一个虚拟单元参数。
在C ++中不是这样。与Haskell和OCaml不同,C ++在f
和f()
之间保持明显的差异。 bind
为您提供前者,因为您可以通过添加()
将其转换为后者。您可以为bind
编写自己的包装器,这样做非常容易。反过来会有点困难。
以下是这种包装器的可能实现:
#include <functional>
#include <utility>
#include <iostream>
template <typename T>
struct is_noargs_callable {
private:
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename U>
static yes test(decltype((std::declval<U>())())*);
template<typename>
static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template <typename T>
struct is_noargs_callable<T()> {
static const bool value = true;
};
template <typename T>
struct is_noargs_callable<T(...)> {
static const bool value = true;
};
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<is_noargs_callable<T>::value, decltype(t())>::type
{
return t();
}
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<!is_noargs_callable<T>::value, T>::type
{
return t;
}
template <typename... Args>
auto apply(Args&&... args) -> decltype(call_me_if_you_can(std::bind(args...))) {
return call_me_if_you_can(std::bind(args...));
}
// testing
void foo(int a, int b, int c) { std::cout << "foo(" << a << "," << b << "," << c << ")"; }
int main ()
{
using namespace std::placeholders;
std::cout << "zero : " ; apply(foo, _1, _2, _3); std::cout << " : " ; apply(foo, _1, _2, _3)(1,2,3); std::cout << std::endl;
std::cout << "one : " ; apply(foo, 1, _1, _2); std::cout << " : " ; apply(foo, 1, _1, _2)(2,3); std::cout << std::endl;
std::cout << "two : " ; apply(foo, 1, 2, _1); std::cout << " : " ; apply(foo, 1, 2, _1)(3); std::cout << std::endl;
std::cout << "three: " ; apply(foo, 1, 2, 3); std::cout << " : "; /* nothing to test here */ std::cout << std::endl;
}
然而,仅仅在这一个地方消除f
和f()
之间的差异并不会影响C ++编程的整体一致性。如果你不喜欢这种区别,可以到处杀死它(或者只是使用Haskell来获得好处)。
答案 1 :(得分:1)
没有消息来源,只是我的意见。
未完成的原因是因为没有理由这样做。如果您知道该函数的所有输入,只需调用它。
如果您使用模板导致了这一点,那么无论如何都需要一致地编写所有代码。这里的一个特例只需要在其他地方使用特殊情况。