C++11 связать и применить?

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 в примере). Возможно ли сделать шаблонное программирование для вызова функции operator operator () в терминальном случае bind?

Другими словами, можно ли написать функцию bind1:

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

, что когда std::is_placeholder<T>::value == 0 для каждого члена args,bind1() может, в дополнение к чему std::bind() вызывает оператор ()?

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 а также f() просто в этом одном месте ИМХО не способствует общей согласованности программирования на C++. Если вам не нравится это различие, убивайте его повсюду (или просто пользуйтесь Хаскеллом для хорошего блага).

Источников для этого нет, только мое мнение.

Причина, по которой это не было сделано, заключается в том, что нет причин делать это. Если вам известны все входные данные функции, просто вызовите ее.

И если вы что-то делаете с шаблонами, которые привели к этому, вам все равно придется последовательно писать весь код. Особый случай здесь потребует только особого случая где-то еще.

Другие вопросы по тегам