Функция C++ связывает повторяющиеся аргументы с функцией curried
Я пытаюсь понять концепцию карринга и вызова функции, которая объединяет три строки, Но передает только две строки и дважды использует второй аргумент.
однако, когда я это делаю, второй аргумент вообще не отправляется функции, и он печатает пустую строку. Это какая-то очевидная ошибка?
string concatthreestrings(string a,string b,string c){
cout<<"Value of A: "<<a<<endl;
cout<<"Value of B: "<<b<<endl;
cout<<"Value of C: "<<c<<endl;
return a+b+c;
}
int main()
{
typedef std::function< string( string,string) > fun_t ;
using namespace std::placeholders;
fun_t fn = std::bind( concatthreestrings, _1, _2, _2);
cout<<endl<<fn( "First","Second")<<endl;
}
Это дает следующий вывод. Не использует _2 дважды означает, что второй аргумент будет передан как для второго, так и для второго третий. Если a использует строку на своем месте, она работает нормально.
2 ответов
копирование строк дорого. С std::bind
думает, что значения заполнителей используются только один раз, он выполняет std::move
На струнах. Это делается для каждого параметра и, как следствие, либо b
или c
- это переезжает, что означает пустую строку.
вы можете изменить это поведение, явно говоря, что вы имеете в виду, передавая аргументы по const-reference:
string concatthreestrings(string const& a,string const& b,string const& c)
теперь он должен работать.
я сделал несколько тестов, используя этот меньший пример, который показывает то же поведение, что и у вас:
#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
по стоимости, в то время как оболочка, возвращенная bind, вероятно возьмите его аргументы по rvalue-reference и отлично-перешлите их. Вместо того, чтобы использовать свой собственный тип, вы должны использовать auto
ключевое слово, так что типа func
будет автоматически выведен компилятором. Если мы изменим main следующим образом, мы получим ожидаемое поведение:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
другое решение-заменить typedef так, чтобы func
принимает свой параметр по ссылке на-const:
typedef std::function< void(string const &) > fn_t;
я действительно не понимаю, почему другой typedef делает не работать... Предположительно строка перемещается, как отметил @ipc, но я не знаю, в какой момент выполнения это происходит. Я даже не уверен, что это стандартное поведение, так как function
и обертка вернулась bind
использование переадресации. Возможно, GCC включает некоторые оптимизации, которые перемещают аргументы оболочки, когда они передаются по значению?
редактировать
я сделал несколько тестов, оказывается, реализация GCC std::function
осуществляет движение по его аргументам, в то время как обертка возвращается std::bind
нет. Я все еще не знаю, является ли это стандартным, я собираюсь написать вопрос об этом.