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は完全に部分的な適用ではないことがわかりました。したがって、質問の2番目の部分では、 std::bind のようなものをどのように記述できますが、部分的な適用を行いますか? bind(bind(f,1,_1),"Hi!")()最終的な 0-ary 関数を呼び出して結果の値を返すことはわかっています (1Hi例では表示しています)。バインドの端末ケースで関数呼び出し演算子()を呼び出すテンプレートプログラミングを行うことは可能ですか?

言い換えれば、関数を書くことは可能ですか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++ ではそうではありません。C++ は、Haskell や OCaml とは異なり、 と の明確な違いを維持し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ただし、この 1 か所だけでとの違いをf()なくしても、C++ プログラミングの全体的な一貫性には貢献しません。区別が気に入らない場合は、どこでもそれを殺してください (または、Haskell を大いに活用してください)。

于 2014-01-21T04:28:13.033 に答える