c ++ 11绑定并申请?

时间:2014-01-21 02:14:15

标签: c++ c++11 stdbind

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()?

2 个答案:

答案 0 :(得分:2)

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

在OCaml中,根本没有无参数函数,需要添加一个虚拟单元参数。

在C ++中不是这样。与Haskell和OCaml不同,C ++在ff()之间保持明显的差异。 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来获得好处)。

答案 1 :(得分:1)

没有消息来源,只是我的意见。

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

如果您使用模板导致了这一点,那么无论如何都需要一致地编写所有代码。这里的一个特例只需要在其他地方使用特殊情况。