2

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 元函数并返回结果值(1Hi在示例中打印)。是否可以做模板编程在bind的终端情况下调用函数调用operator()?

换句话说,是否可以编写一个函数bind1

template< class R, class F, class... Args >
bind1( F f, Args... args )

,这样std::is_placeholder<T>::value == 0对于 的每个成员argsbind1()除了什么之外,还可以std::bind()调用 operator() 吗?

4

2 回答 2

2

没有参数的函数只是 Haskell 中的一个值。你不调用它,你只是使用它。由于没有副作用,因此没有可观察到的差异。

在 OCaml 中根本没有无参数函数,要获得类似的东西,您需要添加一个虚拟单元参数。

在 C++ 中并非如此。f与 Haskell 和 OCaml 不同,C++ 在和之间保持明显的区别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;
}

然而,在这一个地方消除和之间的区别ff()不能恕我直言,有助于 C++ 编程的整体一致性。如果您不喜欢这种区别,请在任何地方杀死它(或者只是为您使用 Haskell)。

于 2014-01-21T04:28:13.033 回答
1

没有这方面的来源,只是我的看法。

没有这样做的原因是因为没有理由这样做。如果您知道该函数的所有输入,只需调用它即可。

而且,如果您正在使用导致这种情况的模板进行某些操作,那么无论如何您都需要一致地编写所有代码。这里的特殊情况只需要其他地方的特殊情况。

于 2014-01-21T02:21:13.630 回答