Для возврата двух значений я использую std::pair
(обычно typedef'd). Вы должны посмотреть на boost::tuple
(в C ++ 11 и новее, есть std::tuple
) для более чем двух результатов возврата.
С введением структурированного связывания в C ++ 17 возвращение std::tuple
должно, вероятно, стать принятым стандарт.
Решение OO для этого состоит в создании класса отношения. Это не потребует никакого дополнительного кода (что бы сэкономить), было бы значительно чище / яснее и предоставило бы вам некоторые дополнительные рефакторинги, позволяющие очищать код вне этого класса.
На самом деле я думаю, что кто-то рекомендуется вернуть структуру, которая достаточно близка, но скрывает намерение, что это должен быть полностью продуманный класс с конструктором и несколькими методами, по сути, «метод», который вы первоначально упоминали (как возвращение пары), должен вероятно, будет членом этого класса, возвращая экземпляр самого себя.
Я знаю, что ваш пример был просто «примером», но факт в том, что, если ваша функция не делает больше, чем любая функция должна делать, Если вы хотите, чтобы он возвращал несколько значений, вы почти наверняка потеряли объект.
Не бойтесь создавать эти крошечные классы, чтобы делать небольшие куски работы - это волшебство OO - вы заканчиваете до тех пор, пока каждый метод не будет очень маленьким и простым, а каждый класс будет небольшим и понятным.
Еще одна вещь, которая должна была быть индикатором того, что что-то не так: в OO у вас практически нет данных - OO не собирается передавать данные, классу нужно управлять и манипулировать собственными данными внутри, любые передачи данных (включая аксессоры) являются признаком того, что вам может потребоваться переосмыслить что-то ..
С C ++ 17 вы также можете вернуть одно или более неизменяемых / непокрытых значений (в некоторых случаях). Возможность возврата неизменяемых типов осуществляется с помощью новой гарантированной оптимизации возвращаемого значения, и она прекрасно сочетается с агрегатами и тем, что можно назвать конструкторами шаблона .
template<typename T1,typename T2,typename T3>
struct many {
T1 a;
T2 b;
T3 c;
};
// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;
auto f(){ return many{string(),5.7, unmovable()}; };
int main(){
// in place construct x,y,z with a string, 5.7 and unmovable.
auto [x,y,z] = f();
}
Симпатичная вещь в том, что гарантировано не вызвать любого копирования или перемещения. Вы можете сделать пример many
struct variadic тоже. Дополнительная информация:
Используйте конструкцию или класс для возвращаемого значения. Использование std::pair
может работать пока, но
Возвращение структуры с самодокументируемыми именами переменных переменных вероятнее всего быть менее подверженным ошибкам для тех, кто использует вашу функцию. Надевая шляпу моего сотрудника на мгновение, ваша структура divide_result
легко для меня, потенциального пользователя вашей функции, сразу же понять через 2 секунды. Посылка с параметрами вывода или таинственными парами и кортежами потребует больше времени для чтения и может быть использована неправильно. И, скорее всего, даже после использования функции несколько раз я до сих пор не помню правильный порядок аргументов.
Если ваша функция возвращает значение через ссылку, компилятор не может сохранить его в регистре при вызове других функций, потому что теоретически первая функция может сохранить адрес переменной, переданной ей в глобально доступной переменной, и любой последующий вызываемые функции могут изменить его, поэтому компилятор будет иметь (1) сохранить значение из регистров обратно в память перед вызовом других функций и (2) перечитать его, когда это необходимо из памяти, после любого из таких вызовов.
Если вы вернетесь по ссылке, оптимизация вашей программы будет страдать
Лично мне обычно не нравятся возвращаемые параметры по ряду причин:
У меня также есть некоторые оговорки в отношении метода пары / кортежа. Главным образом, часто нет естественного порядка для возвращаемых значений. Как читатель кода узнает, является ли результат. Первым является фактор или остаток? И разработчик мог бы изменить порядок, который нарушил бы существующий код. Это особенно коварно, если значения одного типа, так что никакая ошибка компилятора или предупреждение не будут сгенерированы. Фактически, эти аргументы применимы и к возвращаемым параметрам.
Вот еще один пример кода, этот бит немного менее тривиальный:
pair<double,double> calculateResultingVelocity(double windSpeed, double windAzimuth,
double planeAirspeed, double planeCourse);
pair<double,double> result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.first << endl;
cout << result.second << endl;
Выполняет ли это печать на земле и курс, или курс и путевая? Это не очевидно.
Сравните с этим:
struct Velocity {
double speed;
double azimuth;
};
Velocity calculateResultingVelocity(double windSpeed, double windAzimuth,
double planeAirspeed, double planeCourse);
Velocity result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.speed << endl;
cout << result.azimuth << endl;
Я думаю, что это яснее.
Итак, я считаю, что мой первый выбор в целом - это метод построения , Идея пары / кортежа, вероятно, является отличным решением в некоторых случаях. Я хотел бы избежать возможных параметров возврата.
struct
, подобное Velocity
, является хорошим. Однако одна проблема заключается в том, что она загрязняет пространство имен. Я полагаю, что с C ++ 11 struct
может иметь длинное имя типа, и можно использовать auto result = calculateResultingVelocity(...)
.
– Hugues
12 February 2013 в 07:06
struct { int a, b; } my_func();
. Это можно использовать как это: auto result = my_func();
. Но C ++ не позволяет этого: «новые типы не могут быть определены в возвращаемом типе». Поэтому мне нужно создать такие структуры, как struct my_func_result_t
...
– anton_rh
21 April 2016 в 06:14
auto
, поэтому auto result = my_func();
тривиально можно получить.
– ildjarn
15 January 2017 в 02:11
std::pair<int, int> divide(int dividend, int divisor)
{
// :
return std::make_pair(quotient, remainder);
}
std::pair<int, int> answer = divide(5,2);
// answer.first == quotient
// answer.second == remainder
std :: pair - это, по сути, ваше структурное решение, но уже определенное для вас и готовое к адаптации к любым двум типам данных.
Я склонен использовать out-vals в таких функциях, потому что я придерживаюсь парадигмы функции, возвращающей коды успеха / ошибки, и мне нравится сохранять вещи одинаковыми.
Существует прецедент для возврата структур в стандарте C (и, следовательно, C ++) с функциями div
, ldiv
(и в C99, lldiv
) из <stdlib.h>
(или <cstdlib>
).
«Смешение возвращаемого значения и возвращаемых параметров» обычно является наименее чистым.
Наличие функции возвращает статус и возвращает данные через возвращаемые параметры в C; это менее очевидно в C ++, где вы могли бы использовать исключения для ретрансляции информации об отказах.
Если имеется более двух возвращаемых значений, то, вероятно, лучше всего подходит структура-подобный механизм.
Здесь я пишу программу, которая возвращает несколько значений (более двух значений) в c ++. Эта программа является исполняемой в c ++ 14 (G ++ 4.9.2). Программа похожа на калькулятор.
# include <tuple>
# include <iostream>
using namespace std;
tuple < int,int,int,int,int > cal(int n1, int n2)
{
return make_tuple(n1/n2,n1%n2,n1+n2,n1-n2,n1*n2);
}
int main()
{
int qut,rer,add,sub,mul,a,b;
cin>>a>>b;
tie(qut,rer,add,sub,mul)=cal(a,b);
cout << "quotient= "<<qut<<endl;
cout << "remainder= "<<rer<<endl;
cout << "addition= "<<add<<endl;
cout << "subtraction= "<<sub<<endl;
cout << "multiplication= "<<mul<<endl;
return 0;
}
Итак, вы можете четко понимать, что таким образом вы можете вернуть несколько значений из функции. используя std :: pair, могут возвращаться только 2 значения, а std :: tuple может возвращать более двух значений.
auto
на cal
, чтобы сделать это еще более чистым. (ИМО).
– sfjac
19 April 2015 в 14:53
вместо того, чтобы возвращать несколько значений, просто верните один из них и сделайте ссылку других в требуемой функции, например:
int divide(int a,int b,int quo,int &rem)
Альтернативы включают в себя массивы, генераторы и инверсию управления , но здесь не подходит.
Некоторые (например, Microsoft в историческом Win32) имеют тенденцию использовать ссылочные параметры для простоты, потому что ясно, кто распределяет и как он будет выглядеть в стеке, уменьшает распространение структур и позволяет получить отдельное возвращаемое значение для успеха.
«Чистые» программисты предпочитают структуру , предполагая, что - значение функции (как это имеет место здесь), а не то, что коснулось функции. Если у вас была более сложная процедура или что-то с состоянием, вы, вероятно, использовали бы ссылки (при условии, что у вас есть причина не использовать класс).
Я бы сказал, что нет предпочтительного метода, все зависит от того, что вы собираетесь делать с ответом. Если результаты будут использоваться вместе в дальнейшей обработке, тогда структуры имеют смысл, если бы я не стал передавать их в качестве отдельных ссылок, если бы функция не использовалась в составном заявлении:
x = divide( x, y, z ) + divide( a, b, c );
Я часто предпочитаю передавать «внешние структуры» по ссылке в списке параметров, вместо того, чтобы иметь пропуск накладных расходов на копирование новой структуры (но это потение малым материалом).
void divide(int dividend, int divisor, Answer &ans)
Изменились ли параметры? Параметр, отправленный как ссылка, указывает на то, что значение изменится (в отличие от ссылки на константу). Разумное именование также устраняет путаницу.
В C ++ 11 вы можете:
#include <tuple>
std::tuple<int, int> divide(int dividend, int divisor) {
return std::make_tuple(dividend / divisor, dividend % divisor);
}
#include <iostream>
int main() {
using namespace std;
int quotient, remainder;
tie(quotient, remainder) = divide(14, 3);
cout << quotient << ',' << remainder << endl;
}
В C ++ 17:
#include <tuple>
std::tuple<int, int> divide(int dividend, int divisor) {
return {dividend / divisor, dividend % divisor};
}
#include <iostream>
int main() {
using namespace std;
auto [quotient, remainder] = divide(14, 3);
cout << quotient << ',' << remainder << endl;
}
или с помощью структур:
#include <tuple>
auto divide(int dividend, int divisor) {
struct result {int quotient; int remainder;};
return result {dividend / divisor, dividend % divisor};
}
#include <iostream>
int main() {
using namespace std;
auto result = divide(14, 3);
cout << result.quotient << ',' << result.remainder << endl;
// or
auto [quotient, remainder] = divide(14, 3);
cout << quotient << ',' << remainder << endl;
}
struct
за пределы тела функции и замените auto
возвращать функцию с помощью result
.
– pepper_chico
11 July 2017 в 15:43
divide
в отдельный файл cpp? Я получаю ошибку error: use of ‘auto divide(int, int)’ before deduction of ‘auto’
. Как я могу это решить?
– Adriaan
23 February 2018 в 21:26
Boost tuple был бы моим предпочтительным выбором для обобщенной системы возврата более одного значения из функции.
Возможный пример:
include "boost/tuple/tuple.hpp"
tuple <int,int> divide( int dividend,int divisor )
{
return make_tuple(dividend / divisor,dividend % divisor )
}
Мы можем объявить такую функцию, чтобы она возвращала определенную пользователем структуру типа или указатель на нее. И по свойству структуры мы знаем, что структура в C может содержать несколько значений асимметричных типов (т. Е. Одна переменная int, четыре переменные char, две переменные float и т. Д.)
Почему вы настаиваете на функции с несколькими возвращаемыми значениями? С помощью OOP вы можете использовать класс, предлагающий регулярную функцию с единственным возвращаемым значением, и любое количество дополнительных «возвращаемых значений», как показано ниже. Преимущество заключается в том, что у вызывающего есть возможность взглянуть на дополнительные элементы данных, но это не требуется для этого. Это предпочтительный метод для сложной базы данных или сетевых вызовов, где может потребоваться много дополнительной информации о возврате в случае возникновения ошибок.
Чтобы ответить на ваш исходный вопрос, в этом примере есть метод возврата частного, это то, что может понадобиться большинству абонентов, и, кроме того, после вызова метода вы можете получить остаток в качестве элемента данных.
class div{
public:
int remainder;
int quotient(int dividend, int divisor){
remainder = ...;
return ...;
}
};
Это полностью зависит от фактической функции и значения нескольких значений и их размеров:
std::tuple
. – Ferruccio 20 October 2011 в 11:32std::tie
stackoverflow.com/a/2573822/502144 – fdermishin 12 May 2014 в 09:44