Я сделал несколько тестов с использованием этого меньшего примера, который демонстрирует такое же поведение у вас есть:
#include <functional>
#include <iostream>
#include <string>
using std::string;
void print(string s1, string s2)
{
std::cout << s1 << s2 << '\n';
}
int main()
{
using namespace std::placeholders;
typedef std::function< void(string) > fn_t;
fn_t func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foo
Обратите внимание, что я определил строковый объект с именем «Foo», вместо того, чтобы использовать строковые литералы. Поведение такое же, поэтому проблема не связана с этим.
Я думаю, проблема связана с вашим typedef. Возврат bind
(который не указан) передается функции, принимающей string
по значению, в то время как обертка, возвращаемая связыванием, вероятно, принимает свои аргументы с помощью rvalue-reference и отлично передает их. Вместо использования своего собственного typedef вы должны использовать ключевое слово auto
, так что тип func
будет автоматически выведен компилятором. Если мы изменим основные следующим образом, мы получаем ожидаемое поведение:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
Другим решением является заменить ЬурейуЮ так, что func
берет свой параметр в виде ссылки-на-ПОСТОЯННЫЙ:
typedef std::function< void(string const &) > fn_t;
Я не «По-настоящему понять, почему другой typedef не работает ... Предположительно, строка перемещается, как заметил @ipc, но я не знаю, в какой момент выполнения это происходит. Я даже не уверен, что это стандартное поведение, поскольку как function
, так и обертка, возвращаемая bind
, должны использовать идеальную пересылку. Возможно, GCC включает некоторые оптимизации, которые перемещают аргументы оболочки, когда они передаются по значению?
Редактировать
Я сделал несколько тестов, оказывается реализация GCC по std::function
выполняет движение по своим аргументам, в то время как возвращение обертки std::bind
не делает. Я до сих пор не знаю, стандартно ли это, я собираюсь написать вопрос об этом.
Очень интересный вопрос, я бы не ожидал такого поведения! –
Просто добавьте исправление: на самом деле это не карри. Привязанными аргументами и каррированием являются две очень похожие, но все же разные операции, которые не следует путать. Currying означает функцию, которая принимает функцию N аргументов и превращает ее в функцию одного аргумента, которая возвращает функцию одного аргумента, которая возвращает функцию одного аргумента ... (repeat n Times). Вы можете использовать 'std :: bind' для реализации функции curry, которая делает это для вас (в некоторой степени). Аналогичным образом вы можете использовать currying для реализации привязки аргументов в способе 'std :: bind'. – LiKao
@LiKao: Действительно, 'bind' разрешает [частичное приложение] (http://en.wikipedia.org/wiki/Partial_application), а не currying. –