Варианты возврата нескольких типов из метода

В данный момент я изучаю C++ (начинающий). Мне нужен метод для изменения нескольких переменных за его пределами, которые, если я правильно понимаю, не будут/не смогут измениться за пределами этой функции, если не будет указан и возвращен определенный тип. Я также знаю, что не могу возвращать из функции несколько типов.

struct multiTypes {
    int i = 0;
    float f = 1.0;

    std::string a = "testing";
};

multiTypes test() {
    multiTypes mT;
    mT.i += 2;

    return mT;
}

int main() {

    std::cout << test().i << '\n';
    std::cout << test().f << '\n';
    std::cout << test().a << '\n';
}

Хотя это работает, мне было интересно, какие еще существуют альтернативы для достижения того же результата?

«Мне нравится выполнять несколько операций в методе и изменять несколько переменных за его пределами, которые, если я правильно понимаю, не будут/не смогут измениться вне области действия этой функции, если только не будет указан и возвращен определенный тип.. ..» Это не имеет смысла, по моему мнению.

user12002570 20.08.2024 16:16

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

Austin 20.08.2024 16:17

«есть ли альтернативное или лучшее (традиционное или даже производительное) решение?...» В чем проблема с текущим кодом? Также вы уверены, что не занимаетесь микрооптимизацией?

user12002570 20.08.2024 16:17

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

Some programmer dude 20.08.2024 16:17

Как правило, struct практически никогда не следует использовать в C++. Прежде чем приступить к изучению C++, вы должны уже знать об объектно-ориентированном проектировании и классах. Если вы этого не сделаете, есть гораздо более простые языки, которые лучше использовать при изучении самого объектно-ориентированного программирования.

Lundin 20.08.2024 16:20

@user12002570 user12002570 Нет проблем. Как я уже сказал, я сейчас учусь и вообще мне интересно.

stackaccount 20.08.2024 16:21

вы бы не вызывали функцию каждый раз, когда хотите получить доступ к члену структуры, а скорее вызывали бы multiType x = test();, но в остальном в вашем подходе нет ничего плохого

463035818_is_not_an_ai 20.08.2024 16:21

@Лундин, это ужасное практическое правило. Структура ОП совершенно кромулентна. C++ — многопарадигмальный язык.

Caleth 20.08.2024 16:23

Примечание: ничто в этом коде не требует дополнительных вещей, которые делает std::endl. Используйте '\n', чтобы завершить строку, если у вас нет веской причины не делать этого.

Pete Becker 20.08.2024 16:23

@463035818_is_not_an_ai или auto [x, y, z] = test();

Caleth 20.08.2024 16:23

@Caleth Если вы не используете объектно-ориентированный дизайн, вы делаете это неправильно. Новичкам бесполезно сначала научиться делать что-то неправильно, а потом от всего этого отучиться. Класс со всеми открытыми членами почти всегда является неправильным дизайном. И это важно для этого вопроса, потому что вместо этого, вероятно, следует сделать std::cout << test << std::endl; или, возможно, test.str() или что-то подобное.

Lundin 20.08.2024 16:26

@Лундин multiTypes — отличный специалист по безопасности. У него нет инвариантов, которые нужно поддерживать.

Caleth 20.08.2024 16:29

Какой лучший способ научить новичка использовать пользовательскую структуру данных, основан на мнениях. кед. Голосование за закрытие

463035818_is_not_an_ai 20.08.2024 16:30

@Caleth Также не существует такого понятия, как «мультипарадигмальный» язык, по той же причине, что и не существует такого понятия, как «объектно-ориентированный язык». Есть языки с поддержкой объектно-ориентированного программирования, а есть языки без нее. Есть правильно спроектированные программы, а есть плохие. Независимо от языка, нет оправдания тому, чтобы практиковать плохой дизайн или внушать новичкам, как делать плохой дизайн. Просто посмотрите на весь ущерб, нанесенный злой книгой K&R - она ​​учит синтаксису и функциям в основном хорошо, но преподаваемый стиль кодирования должен был быть объявлен преступным.

Lundin 20.08.2024 16:31

@463035818_is_not_an_ai Спасибо, это было просто для тестирования.

stackaccount 20.08.2024 16:33

@user12002570 user12002570 Что для тебя не имеет смысла? Возможно, я смогу уточнить.

stackaccount 20.08.2024 16:33

Использование структуры вполне нормально

Pepijn Kramer 20.08.2024 16:33

@Лундин, тебе не обязательно писать в объектно-ориентированном стиле на C++. Вы можете писать в функциональном или процедурном стиле. ОО — неправильный способ написания всего программного обеспечения.

Caleth 20.08.2024 16:33

@Austin В настоящее время сосредоточен на различных способах структурирования программы и доступа к различным областям/наследованию/полиморфизму. Так что никакой острой актуальной проблемы как таковой нет.

stackaccount 20.08.2024 16:33

@Lundin В чем проблема, начиная с C++, если я знаю, что хочу его использовать? Я могу правильно выучить его с нуля, и мне не нужно сначала тратить больше времени на изучение другого языка, чтобы достичь желаемого результата (знание того, как писать код на C++). Я работаю в другой сфере, это побочное дело

stackaccount 20.08.2024 16:33

@stackaccount — Добро пожаловать в C++. Не существует более великого сообщества, в котором мы все были бы полностью согласны с какой-то лучшей практикой для всего. Вместо этого язык используется для множества разных вещей в отдельных сообществах с разными правилами. IMO, возвращение структуры с открытыми членами вполне нормально, если это единственное использование этой структуры. В противном случае вам было бы лучше использовать класс, управляющий частными членами. ЮММВ.

BoP 20.08.2024 16:37

@Caleth Частная инкапсуляция + автономные объекты/модули — правильный способ написания всего программного обеспечения. И это 2 из 3 столпов объектно-ориентированного подхода, причем наследование является третьим, и его просто «приятно иметь». Имейте в виду, что я программирую практически исключительно на C, но это не мешает мне писать правильно спроектированные программы. «Функциональный стиль» — это просто причудливое название для «крыльев», или, если хотите, «не разрабатывать программы» — его на самом деле не существует.

Lundin 20.08.2024 16:37

@stackaccount Дело в том, что объектно-ориентированный дизайн - это концепция проектирования программ, не зависящая от языка, которую полезно знать прежде всего. C++ очень сложен, даже если вы заранее знаете ОО. Даже для того, кто, скажем так, является опытным Java-программистом, но никогда не программировал на C++, будут странные и экзотические сюрпризы. Вы можете изучить объектно-ориентированный подход, изучая C++ (это то, что я когда-то делал), но я не рекомендую это делать.

Lundin 20.08.2024 16:39

Это быстро отвлекает. Обсуждение объектно-ориентированного подхода и других парадигм лучше всего подходит для обсуждения в чате, а не для комментариев по этому вопросу. Конечно, поскольку вопрос по своей сути основан на мнениях, это естественное развитие событий, но лучшее действие в этом случае — проголосовать за закрытие вопроса.

Chris 20.08.2024 16:40

@Lundin, комитет C++ не согласился с вами еще в 2020 году

Caleth 20.08.2024 16:41

@Lundin Разве ООП не приводит к увеличению длины программ и, следовательно, к увеличению времени выполнения? Я не рекламирую это, просто я что-то прочитал. Не имея опыта, прямо сейчас я думаю, что в целом мне хотелось бы писать так, чтобы А) было чисто (просто в обслуживании и развитии), Б) работало по назначению и без проблем, и В) было ориентировано на производительность. Мне нравится, чтобы программы были быстрыми. Поэтому, учитывая это, я бы выбрал то, что решает любую проблему, с которой я сталкиваюсь, наилучшим из известных мне способов. Отсюда мой первоначальный вопрос.

stackaccount 20.08.2024 16:44

@Caleth Тот факт, что вы можете писать «функторы» и тому подобное с помощью struct, не означает, что вам это нужно. То, что когда-то называлось STL, использует структуру по традиции, а не по каким-то причинам. Большинству вещей в C++ не хватает обоснования того, почему они существуют на самом деле.

Lundin 20.08.2024 16:45

@ Крис, позволь мне отредактировать вопрос.

stackaccount 20.08.2024 16:45

Если вопрос закрыт, пожалуйста, отредактируйте его. Закрытые вопросы можно открыть повторно, если они сочтены соответствующими правилам переполнения стека. Как спросить

Chris 20.08.2024 16:46

@stackaccount Нет, объектно-ориентированный подход — это способ разработки программ, он очень мало влияет на производительность. Точно так же C++ в большинстве случаев не обязательно медленнее C.

Lundin 20.08.2024 16:46

@Lundin std::in_out_out_result — это структура с тремя общедоступными элементами данных (и преобразованиями), которая существует для присвоения осмысленных имен трем значениям, которые все хотят вернуть из одной функции. ОП именно об этом и спрашивает

Caleth 20.08.2024 16:49

@ Крис, я изменил его на более общий вопрос, не основанный на мнениях.

stackaccount 20.08.2024 16:53

Итог: C++ предоставляет практически безграничные возможности для написания плохих программ. Но это не значит, что нам следует это делать. Аналогично, то, что функция существует в C++, не означает, что мы должны ее использовать. Понимание этого является ключом к написанию удобных в сопровождении программ на C++. В противном случае через год вы будете сидеть в каком-то аду метапрограммирования шаблонов, размышляя о том, как реализовать Z в вашей проблеме XYZ, вместо того, чтобы разрабатывать приложение A, над которым, по мнению вашего босса, вы работаете.

Lundin 20.08.2024 16:59

@Lundin Является ли ваша проблема с использованием структур тем фактом, что они по умолчанию общедоступны? Похоже, большинство с вами не согласны. Все, что я знаю, это то, что в учебных пособиях они используются. PS: Я сам себе начальник, в другой сфере, кроме сути.

stackaccount 20.08.2024 17:04

Еще не упомянуто: std::variant может справиться с некоторыми головными болями за вас. Возвращаемые значения могут быть совершенно несвязанными типами. По крайней мере, для изучения современного C++ это весьма полезно знать. Однако я бы никого не винил за выбор более простого способа, как показано в вопросе.

Peter Pointer 20.08.2024 17:08

@stackaccount Да, в этом и проблема — в остальном они на 100% эквивалентны class, поэтому нет причин, по которым вам не следует всегда использовать class. И я не знаю, смеяться мне или плакать по этому поводу. Вот я, в основном программист на C, который избегает C++, когда это возможно, - читаю лекцию будущим программистам C++ использовать объектно-ориентированный дизайн, который, очевидно, сбивает их с толку. Печальное положение дел.

Lundin 20.08.2024 17:08

@Lundin Ха, такова жизнь. Если вас это утешит, структура, с которой я на самом деле возюсь, находится внутри класса;)

stackaccount 20.08.2024 17:10

@Питер Пойнтер, мне неловко признаться, я попробовал std::variant и по какой-то причине не получилось.

stackaccount 20.08.2024 17:15

@stackaccount О, я уверен, что вы сможете найти для него хороший учебник (поиск варианта учебника по C++ должен найти его для вас). Я просто не буду ссылаться на него, поскольку однажды он может устареть или перестать существовать.

Peter Pointer 20.08.2024 17:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
39
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, вполне нормально определить тип для хранения нескольких возвращаемых значений для определенной функции.

Взгляните на std::in_in_out_result , он по сути такой же, как ваш тип, и используется рядом функций в стандартной библиотеке.

Вы должны дать типу и его членам значимые имена, но нет никакого контекста относительно того, какими они будут в минимальном примере в вашем вопросе.

Какие еще альтернативы существуют для достижения того же результата?

Если у вас есть значимые имена, это предпочтительнее, чем возврат teststd::tuple<int, float, std::string>, который является еще одним типом, который может хранить эти три значения.

std::tuple<int, float, std::string> acceptable_test() {
    return { 2, 1.0, "testing" };
}

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

void bad_test(int& i, float& f, std::string& a) {
    i = 2;
    f = 1.0;
    a = "testing";
}

Также может быть полезно перегрузить << для этого типа, чтобы можно было печатать std::cout << mT << '\n'.

Chris 20.08.2024 16:56

@ Крис, это зависит. Бывают ситуации, когда auto [x, y, z] = test(); std::cout << x << y << z << '\n'; более понятен

Caleth 20.08.2024 16:57

Спасибо, @Калет! Обычно я использую осмысленные имена. Иначе я бы заблудился. Также я не знал, что это std::tuple<int, float, std::string> может содержать несколько типов, спасибо :)

stackaccount 20.08.2024 17:08

Другие вопросы по теме

Похожие вопросы

Сопоставление класса перечисления с перегрузкой функции
Почему синтаксис C# обрабатывает ptr = null иначе, чем разыменование указателя в C++?
Что происходит в C++, когда rvalue типа, доступного только для перемещения, передается функции по значению?
Можно ли вернуть переменную и обновить ее одним оператором вместо того, чтобы сначала копировать переменную?
Вывести класс шаблона с уменьшенным количеством параметров шаблона
C++: Что означает (-1) в конце списка параметров этой функции?
Функция Sony Camera Remote SDK Connect() не возвращает дескриптор устройства
«Ошибка файловой системы: невозможно увеличить рекурсивный итератор каталога: разрешение отклонено» в каталоге 0777
Влияет ли знак на точность и точность чисел с плавающей запятой?
Я пытался создать общие библиотеки C++ для Python, используя cmake и pybind11, но получаю ошибки, которые не знаю, как исправить