Как сделать чтобы функция возвращала 2 значения c

Добавил пользователь Skiper
Обновлено: 05.10.2024

Есть ли предпочтительный способ возврата нескольких значений из функции С++? Например, представьте себе функцию, которая делит два целых числа и возвращает как фактор, так и остаток. Один из способов, который я обычно вижу, - использовать ссылочные параметры:

Вариант состоит в том, чтобы вернуть одно значение и передать другое через опорный параметр:

Другим способом было бы объявить структуру, содержащую все результаты, и вернуть ее:

Является ли один из этих способов вообще предпочтительным, или есть другие предложения?

Изменить: в коде реального мира может быть более двух результатов. Они также могут быть разных типов.

Для возврата двух значений я использую std::pair (обычно typedef'd). Вы должны посмотреть на boost::tuple (в C++ 11 и более новый, там std::tuple ) для более чем двух результатов возврата.

С введением структурированного связывания в C++ 17, возвращение std::tuple должно стать стандартным.

+1 за кортеж. Имейте в виду последствия для производительности больших объектов, возвращающихся в структуре, по сравнению с передачей по ссылке.

Если вы собираетесь использовать кортежи, почему бы не использовать их и для пар. Почему есть особый случай?

Может ли boost :: tuple обрабатывать разные типы в одном и том же кортеже? Может быть, вы можете использовать boost :: any с ним.

Я предпочитаю структуры в целом, но кортежи потрясающие из-за std::tie(var_a, var_b) = func_returning_tuple();

В С++ 11 вы можете:

или со структурами:

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

@UchiaItachi То же самое касается параметров функций, вы можете давать им имена, но язык даже не применяет это, и имена параметров не имеют значения на сайте вызова при чтении. Кроме того, при одном возврате у вас просто есть тип, но наличие имени также может быть полезным, с кортежами вы просто удваиваете проблему, так что, по-моему, языку просто не хватает самодокументирования несколькими способами, не только этим.

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

@Slava, вы не можете определить тип прямо в сигнатуре функции, вам нужно будет объявить тип снаружи и использовать его в качестве возвращаемого типа, как это обычно делается (просто переместите строку struct за пределы тела функции и замените auto возврат функции на result

@Adriaan Adriaan вы решаете это, как я объясняю в моем предыдущем комментарии. Вы не можете иметь прототипы с auto возвратом в заголовках, тип возврата должен быть выведен из кода.

Лично мне обычно не нравятся возвращаемые параметры по ряду причин:

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

У меня также есть некоторые оговорки в отношении метода пары/кортежа. Главным образом, часто нет естественного порядка для возвращаемых значений. Как читатель кода узнает, является ли результат. Первым является фактор или остаток? И разработчик мог бы изменить порядок, который нарушил бы существующий код. Это особенно коварно, если значения одного типа, так что никакая ошибка компилятора или предупреждение не будут сгенерированы. Фактически, эти аргументы применимы и к возвращаемым параметрам.

Вот еще один пример кода, это немного менее тривиально:

Является ли эта печатная версия и курс, курс или курс? Это не очевидно.

Сравните с этим:

Я думаю, что это яснее.

Итак, я считаю, что мой первый выбор в целом - это метод структуры. Идея пары/кортежа, вероятно, является отличным решением в некоторых случаях. Я хотел бы избежать возможных параметров возврата.

Предложение об объявлении struct подобной Velocity является хорошим. Тем не менее, одна проблема заключается в том, что это загрязняет пространство имен. Я полагаю, что в C ++ 11 struct может иметь длинное имя типа, и можно использовать auto result = calculateResultingVelocity(. ) .

@anton_rh C ++ 14 позволяет возвращать локальные типы с помощью auto , поэтому auto result = my_func(); тривиально доступен.

Около 15 лет назад, когда мы обнаружили повышение, мы часто использовали кортеж, так как это довольно удобно. С течением времени мы столкнулись с недостатком удобочитаемости, особенно для кортежей одного типа (например, кортеж ; какой из них какой). Поэтому в последнее время мы привыкли вводить небольшую структуру POD, где хотя бы имя переменной-члена указывает на что-то разумное.

std:: pair - это, по сути, ваше структурное решение, но уже определенное для вас и готовое к адаптации к любым двум типам данных.

Это сработает для моего простого примера. В целом, однако, может быть возвращено более двух значений.

Это полностью зависит от фактической функции и значения нескольких значений и их размеров:

  • Если они связаны так же, как в примере с вашей долей, я бы пошел с экземпляром структуры или класса.
  • Если они не связаны друг с другом и не могут быть сгруппированы в класс/структуру, возможно, вам следует реорганизовать ваш метод на два.
  • В зависимости от объема памяти, возвращаемого вами, вы можете захотеть вернуть указатель на экземпляр класса или структуру или использовать ссылочные параметры.

Решение OO для этого - создать класс отношения. Это не потребует никакого дополнительного кода (что бы сэкономить), было бы значительно чище/понятнее и предоставило бы вам некоторые дополнительные рефакторинги, позволяющие очищать код вне этого класса.

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

Я знаю, что ваш пример был просто "примером", но факт в том, что, если ваша функция не делает больше, чем любая функция должна делать, если вы хотите, чтобы она возвращала несколько значений, вы почти наверняка потеряете объект.

Не бойтесь создавать эти крошечные классы, чтобы делать небольшие кусочки работы - что волшебство OO - вы в конечном итоге ломаете его, пока каждый метод не будет очень маленьким и простым, а каждый класс будет маленьким и понятным.

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

Возможно ли для функции вернуть два значения? Массив возможен, если оба значения имеют одинаковый тип, но как вы возвращаете два разных значения типа?

Тем не менее, можно использовать другие понятия, чтобы вернуть 2 значения. Первое, что приходит на ум, - это использование типа упаковки, такого как Tuple ,

Tuple Тип доступен только в версии 4.0 и выше. Если вы используете более раннюю версию фреймворка, вы можете создать свой собственный тип или использовать KeyValuePair ,

Другой метод заключается в использовании параметра out (хотя я бы очень рекомендовал подход с кортежем).

Одним словом, нет.

Но вы можете определить struct (или же class в этом отношении) для этого:

Это, конечно, слишком специфично для одной проблемы. Более гибкий подход заключается в определении общего struct лайк Tuple (как предложил JaredPar):

Тогда у вас может быть какой-то метод, который выглядит так:

Это не возможно напрямую. Вам необходимо вернуть один параметр, который объединяет два параметра, или использовать параметры:

Все возможные решения упускают один важный момент; почему вы хотите вернуть два значения из метода? На мой взгляд, есть два возможных случая; а) вы возвращаете два значения, которые действительно должны быть инкапсулированы в одном объекте (например, высота и ширина чего-либо, поэтому вы должны вернуть объект, который представляет это нечто) или б) это запах кода, и вам действительно нужно подумать, почему метод возвращает два значения (например, метод действительно делает две вещи).

Может ли кто-нибудь сказать мне, как вернуть несколько значений из функции?

Пожалуйста, уточните в каком-то примере?

Ваш выбор здесь - либо вернуть структуру с элементами по своему вкусу, либо заставить функцию обрабатывать аргументы с указателями.

Вы не можете сделать это напрямую. Ваши параметры состоят в том, чтобы обернуть несколько значений в структуру или передать их в качестве аргументов указателя функции.

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

Если различные элементы данных являются частью более крупного составного типа данных (такого как почтовый адрес или позиция в заказе клиента или какой-либо другой тип, описываемый несколькими атрибутами), затем определите тип структуры для представления одно значение этого составного типа:

Do not определить структуру для сбора случайных элементов, которые не так или иначе связаны друг с другом; что просто вызовет путаницу для вас и любого, кто должен поддерживать ваш код в будущем.

Если элементы данных не являются функционально связанными, но каким-то образом связаны с операциями (например, данные плюс флаг состояния плюс метаданные об операции или элементах как часть одной операции ввода), затем используйте несколько параметров для записи. Наиболее очевидными примерами являются функции *scanf() в стандартной библиотеке. Существуют также функции strtod() и strtol() , которые преобразуют строковое представление числа; они возвращают преобразованное значение, но они также записывают первый символ, который не был преобразован в отдельный параметр:

Вы можете комбинировать эти подходы; вот пример, вдохновленный некоторой работой, которую я сейчас делаю:

Служба, запрашивающая данные о высоте, возвращает 1-мерную последовательность значений; размеры массива возвращаются как часть метаданных.

Вы можете заказать у нас

VPS (Virtual Private Server, виртуальный выделенный сервер, другое название VDS — Virtual Dedicated Server) — стартовая площадка для крупных проектов, позволяющая более рационально использовать представляемые ресурсы в рамках выбранного тарифа OpenVZ-сервера. OpenVZ — технология виртуализации c общим ядром основной операционной системы без эмуляции отдельного физического сервера. Предлагает меньшую стоимость за счёт низких накладных расходов на виртуализацию. KVM — аппаратная виртуализация, при которой полностью эмулируется физический сервер, что позволяет устанавливать любые операционные системы (Linux, Windows, FreeBSD и другие) и дает гарантированные ресурсы физического сервера. Для всех серверов предоставляется надежная DDOS-защита.

Задание такое : составить функцию, находящую и возвращающую минимальное значение другой функции и максимальный аргумент ( при котором функция принимает минимальное значение) при аргументе, изменяющемся от А до В с шагом Н.

одно значение можно возвращать стандартным образом, второе через параметр - ссылку:
double func(double arg, double &result2)
result2 = . ;
return . ;
>
Пара и структура (в других ответа) - более красивые способы.

Может я дурь сказану, но при описании параметров допускается использование in (входной параметр) и out (возврат). То есть, ни что не мешает наладить сколь угодно большое количество возвращаемых значений через аргументы.

Для таких задач я использую структуры. Логика и намерения должны быть понятны. Можно и как говорят выше, но это неудобно и нарушает логическую связность.

Читайте также: