Как вернуть более одного значения из функции С++?

Мне интересно, могу ли я вернуть более одного значения из функции. Например, рассмотрим такую ​​функцию: расширенный алгоритм Евклида. Основной шаг описывается следующим входом: целые неотрицательные числа a и b; выход представляет собой триплет (d,i,j), такой что d=gcd(a,b)=i*a+j*b. Просто чтобы уточнить цель моего вопроса, я напишу короткий рекурсивный код:

 if (b==0)  return (a,1,0)
      q=a mod b;

пусть r таково, что a=r*b+q;

(d,k,l)=extendedeuclidean(b,q);
  return (d,l,k-l*r); 

Как вернуть тройку?


person dato datuashvili    schedule 07.09.2011    source источник
comment
Подумайте об использовании знаков препинания в следующий раз. Это довольно тяжело читать.   -  person Fiktik    schedule 07.09.2011


Ответы (5)


Просто создайте соответствующую структуру данных, содержащую три значения, и верните ее.

struct extmod_t {
    int d;
    int i;
    int j
    extmod_t(int d, int i, int j) : d(d), i(i), j(j) { }
};

…

extmod_t result = extendedeuclidean(b, q);
return extmod_t(result.d, l, k - l * r);
person Konrad Rudolph    schedule 07.09.2011
comment
только один вопрос как это сделать при рекурсивном вызове функции? - person dato datuashvili; 07.09.2011
comment
@ user466534 Что ты имеешь в виду? Для рекурсии не требуется специальной обработки. - person Konrad Rudolph; 07.09.2011

Вы можете создать std::tuple или boost::tuple (если вы не используете C++0x) из вашей тройной пары и верните ее.

person Tony The Lion    schedule 07.09.2011

Как было предложено Тони Тигром, вы можете использовать tuple. Он включен в стандарт C++11, и новые компиляторы уже поддерживают его. Он также реализован в boost. Для моего компилятора ibm xlC кортеж находится в пространстве имен std::tr1 (пробовал его для MSVC10 — он находится в пространстве имен std).

#include <cstdio>
#include <tuple>

// for MSVC
using namespace std;

// for xlC 
//using namespace std::tr1;

// for boost
// using namespace boost;

typedef tuple<int, float, char> MyTuple;
MyTuple f() {
    return MyTuple(1, 2.0f, '3');
}

int main() {
    MyTuple t = f();
    printf("%i, %f, %c\n", get<0>(t), get<1>(t), get<2>(t));
}

Компиляция xlC для TR1:

xlC -D__IBMCPP_TR1__ file.cpp

Компиляция xlC для повышения:

xlC file.cpp -I/path/to/boost/root
person Anton Daneyko    schedule 07.09.2011

Либо создайте класс, который инкапсулирует триплет, а затем верните экземпляр этого класса, либо используйте 3 параметра по ссылке.

person Branko Dimitrijevic    schedule 07.09.2011
comment
–1 для параметров по ссылке. Это ужасное злоупотребление параметрами, совершенно ненужное и делающее функцию менее удобной в использовании. - person Konrad Rudolph; 07.09.2011
comment
@Konrad Это делает его менее удобным в использовании, только если вызывающая сторона уже готова использовать объект. Если остальная часть кода использует независимые поля, то распаковка возвращаемого объекта может оказаться более уродливой, чем прямая передача полей по ссылке. - person Branko Dimitrijevic; 07.09.2011

Обычно я обнаруживаю, что когда мне нужно вернуть два параметра из функции, полезно использовать STL std::pair.

Вы всегда можете сложить пары внутри друг друга (например, std::pair <int, std::pair <int, int> >) и помочь себе с typedef-ами или определениями, чтобы сделать их более доступными, но когда я когда-либо пытаюсь сделать это, мой код оказывается грязным и непрактичным для повторного использования.

Однако для более чем двух параметров я рекомендую создать собственную структуру данных, содержащую необходимую вам информацию (если вы возвращаете несколько значений, существует высокая вероятность того, что они каким-то образом сильно логически связаны и что вы можете в конечном итоге использовать одну и ту же структуру). опять таки).

Например. Мне нужна была функция, которая возвращала наклон линии (1 параметр), и это было нормально. Затем мне нужно было расширить его, чтобы вернуть оба параметра параметрического представления линии (y = k*x + l). Два параметра, еще нормально. Затем я вспомнил, что линия может быть вертикальной и что я должен добавить еще один параметр, чтобы указать на это (тогда без параметрического представления)... В этот момент стало слишком сложно пытаться обойтись существующими типами данных, поэтому я набрал свой собственную структуру Line и в конечном итоге использовал одну и ту же структуру во всем моем проекте позже.

person penelope    schedule 07.09.2011