Я хочу перегрузить функцию так, чтобы она каким-то образом обрабатывала свой аргумент, а затем возвращала ссылку на аргумент, но если аргумент не изменен, тогда он должен вернуть копию аргумента вместо. После того, как он возился с ним целую вечность, вот что я придумал.Перегрузка функции rvalue
using namespace std;
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string &&in)
{
return move(foo(in));
}
string foo(const string& in)
{
return foo(string(in));
}
Этот код, кажется, работает правильно, но мне интересно узнать, может ли кто-нибудь подумать о лучшем способе его выполнения.
Вот тестовая программа:
int main(void)
{
string var = "world";
const string var2 = "const world";
cout << foo(var) << endl;
cout << var << endl;
cout << foo(var2) << endl;
cout << var2 << endl;
cout << foo(var + " and " + var2) << endl;
return 0;
}
Правильный выход
hello world
hello world
hello const world
const world
hello hello world and const world
Я полагаю, что это было бы немного аккуратнее, если бы я мог это сделать:
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string in)
{
return move(foo(in));
}
Конечно, это не работает, потому что большинство вызовов функций на foo
было бы двусмысленным - включая вызов в foo
сам! Но если бы я мог как-то сказать компилятору расставить приоритеты первого ...
Как я уже сказал, код, который я опубликовал, работает правильно. Главное, что мне не нравится в этом, - это повторяющийся дополнительный код. Если бы у меня была куча таких функций, это стало бы бесполезным, и большинство из них было бы очень повторяющимся. Итак, как вторая часть моего вопроса: может ли кто-нибудь подумать о способе автоматического генерации кода для второй и третьей функций foo
? например
// implementation of magic_function_overload_generator
// ???
string& foo(string &in);
magic_function_overload_generator<foo>;
string& bar(string &in);
magic_function_overload_generator<bar>;
// etc
Это звучит страшно. В зависимости от того, какой тип я передаю функции, результирующее состояние возвращаемого значения * и параметра * может быть совершенно иным. Это просто требует тонких ошибок. Почему бы не позволить пользователю решить, хочет ли он изменить объект на месте или вернуть копию, явно называя разные функции? – jalf
Мне это не кажется особенно страшным, но, возможно, ты прав. То, как я думаю об этом, заключается в том, что функция меняет ввод всякий раз, когда это возможно; но если он не может ... тогда это не так, но он все равно дает правильное возвращаемое значение. То, что я могу использовать для него, - это что-то вроде функции «Пунктуация», которая берет плохо перемежаемую строку и исправляет ее. Возможно, вы захотите отправить результат непосредственно в cout, иначе вы можете выполнить некоторые другие операции над строкой. Поэтому иногда вы можете передавать постоянные значения, а иногда ... ну, вы поняли эту идею. – karadoc
, но моя точка зрения заключается в том, что независимо от того, что происходит или нет, зависит не от того, чего хочет программист, а от некоторых относительно тонких семантических деталей (это тип аргумента const или нет? Является ли это rvalue или нет?), который со временем может легко измениться без того, чтобы программист явно принял решение о том, что «теперь я хочу вернуть копию вместо изменения объекта на месте». Я понимаю, что вы пытаетесь сделать, но это решение, которое программист может легко сделать, и когда у вашей библиотеки неправильное предположение может иметь потенциально очень плохие последствия. – jalf