Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple.
Я просто не могу представить реального случая, где бы подобный подход мог иметь смысл.
Если это обычная функция, возвращающая, например код ошибки, или результат исполнения, который "не поместился" в скалярный тип, то я не вижу смысла пихать определение структуры вовнутрь ее. За сомнительную экономию нескольких идентификаторов и пунктуаций мы получаем:
1. Кишки функции наружу.
2. Невозможность использовать этот тип где либо еще, объявлять его явно.
3. Необходимость лезть в реализацию функции для поиска ее возврата.
Лучше определить структуру явно в заголовке класса.
Если же это какое-то значимое данное, состав которого неочевидным образом определяется на момент компиляции тела функции, то без статической рефлексии или замены на туплы, мы просто не будем знать что с ней делать дальше. Поэтому это тоже не вариант.
Так в каком же случае это полезно?
Здравствуйте, BulatZiganshin, Вы писали: BZ>в результате получаем просто функцию, возвращающую несколько поименованных результатов.
Да. Но при этом:
1. Вынуждены делать функцию инлайн.
2. Не сможем заменить функцию на виртуальную.
3. Не сможем объединить возвращаемый тип с подобными функциями (тут просто просится какой-то struct read_result;).
4. Ограничены одной точкой выхода.
5. Можем получить неочевидые проблемы с выводимыми типами переменных-членов этой структуры.
Но. Опять же — это все до тех пор, пока нет статической рефлексии. Как только оная появится, ценность подобных записей заметно увеличится, и их существование будет оправдано.
Здравствуйте, B0FEE664, Вы писали: BFE>Зачем?
Ну, не inline, а делать потроха функции видимыми снаружи.
// Вместо:class X
{
struct Restult {...};
Result some_function();
}
// Делать:class X
{
auto some_function()
{
// А тут что-то, что требует 100500 заголовков...return {...};
}
}
Нет, я не спорю, любая возможность хороша, есть анонимные функции, будут анонимные классы. Просто ценность такого нововведения для меня сомнительна.
Здравствуйте, Went, Вы писали:
W>>>3. Необходимость лезть в реализацию функции для поиска ее возврата. BFE>>С кодами int, bool или "не дай бог" errno() легче что-ли? W>Я хотя бы знаю, что эта функция возвращает, глянув только на ее заголовок.
Здравствуйте, UA, Вы писали: UA>Ну вернет тебе bytes_read == 8 и что же ты знаешь? UA>* Это прочитано 8 элементов или 4 элемента по 2?
Как правило, мне плевать. Если я читаю байты из потока, то мне нужен просто размер. UA>* Это всего прочитано или только до EOF?
Если меня интересует EOF, я лучше спрошу у файла file->eof()? UA>* Это успел прочитать какой то огрызок данных до возникновения ошибки?
Если произошла ошибка, предпочту словить исключение там, где с ним знают что делать, а не прокидывать коды ошибок через всю Ивановскую.
UA>>Ну вернет тебе bytes_read == 8 и что же ты знаешь? UA>>* Это прочитано 8 элементов или 4 элемента по 2? W>Как правило, мне плевать. Если я читаю байты из потока, то мне нужен просто размер. UA>>* Это всего прочитано или только до EOF? W>Если меня интересует EOF, я лучше спрошу у файла file->eof()? UA>>* Это успел прочитать какой то огрызок данных до возникновения ошибки? W>Если произошла ошибка, предпочту словить исключение там, где с ним знают что делать, а не прокидывать коды ошибок через всю Ивановскую.
Ты путаешь подходы низкого и высокого уровней:
* если тебя интересуют байты значит ты на самом низком уровне со всеми вытекающими (когда нету ни эксепшинов, ни уверенности что данные прочитаются в полном объёме, и никаких file->eof() у тебя не будет, а только указатель или хэндл потока);
* если же ты на объектном уровне то читают уже не байтами, а сразу объектами;
Здравствуйте, Went, Вы писали:
UA>>>>Делали бы так... W>>>Для этого есть туплы. EP>>У их полей нет имён. W>Само собой.
В этом их большАя часть различий (другая часть вытекает из отсутствия compile-time reflection).
С именами полей код получается более выразительным, нежели с безликими first/second/get<I>. Всем известный пример — std::map::insert, но там хоть типы разные.
Здравствуйте, B0FEE664, Вы писали:
W>>1. Кишки функции наружу. BFE>В каком смысле? То, что определение описано внутри функции, а не снаружи? А typedef key key_type; у std::map — это кишки класса наружу? Нет? Почему?
Нет, в том смысле, что я не могу реализовать функцию отдельно от декларации.
W>>2. Невозможность использовать этот тип где либо еще, объявлять его явно. BFE>Это плюс, а не минус. Это не позволит перепутать результат функции с чем-то ещё.
Кому не позволит? Разработчику библиотеки?
W>>3. Необходимость лезть в реализацию функции для поиска ее возврата. BFE>С кодами int, bool или "не дай бог" errno() легче что-ли?
Я хотя бы знаю, что эта функция возвращает, глянув только на ее заголовок.
W>>Лучше определить структуру явно в заголовке класса. BFE>Не легче. Это сильно засоряет scope класса бессмысленными типами имеющими отношение только к конкретным функциям.
А засорять scope обрамляющего пространства имен классами, необходимыми для реализаций этих функций, не жалко? Смотрите пункт 1 — "кишки наружу". Или я что-то не понял в задумке?
BFE>Например, функция std::stod вместо бросания исключения могла бы возвращать результат, код конвертации и указатель на константную строку с описанием ошибки.
И вместо
auto number = std::stod("10.0");
Писать
auto number = std::stod("10.0").result;
?
Ведь сейчас никто не мешает так делать. Заведи шаблон со всеми требуемыми полями и пиши себе:
BZ>>и что возвращает функция int fread(...) ? BZ>>кол-во прочитанных байт? код ошибки? фазу Луны? W>Ну, давайте не заниматься демагогией. Я хотя бы знаю, что это целое. По этому, по названию и сигнатуре функции я в 99% случаев могу предсказать этот результат.
Ну вернет тебе bytes_read == 8 и что же ты знаешь?
* Это прочитано 8 элементов или 4 элемента по 2?
* Это всего прочитано или только до EOF?
* Это успел прочитать какой то огрызок данных до возникновения ошибки?
Здравствуйте, B0FEE664, Вы писали:
BFE>>>Наконец-то можно возвращать структуры определённые внутри, а не вне функции: V>>А в чём трюк то заключается? BFE>Не знаю как вам, а мне часто хочется написать функцию возвращающую код ошибки осмысленным текстом:
Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, BulatZiganshin, Вы писали:
BZ>в результате получаем просто функцию, возвращающую несколько поименованных результатов
Неудобно тут то, что имена результатов можно узнать только в теле функции. Удобнее, что бы он были видны в хедере...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
EP>>А такая функция и будет в header, так как результирующий тип выводится. E>Ну так надо будет ботать код функции, что бы понять чего от ней ждать...
Или в документацию, так же как и в случае с кортежем, также как и в случае с динамически типизированными языками.
E>В чём профит?
Например это как минимум лучше выглядит на стороне пользователя чем при возвращении безликого кортежа.
Почему вообще возвращают кортежи (не считая TemplateMP, и случаев где действительно имеет место набор безликих значений) — другой вопрос.
Здравствуйте, T4r4sB, Вы писали:
BFE>>Наконец-то можно возвращать структуры определённые внутри, а не вне функции: TB>Можно? А в какой именно не-сырой версии Студии?
Согласно стандарту — можно, а вот на практике...
Мы только недавно на С++11 перешли.
Здравствуйте, B0FEE664, Вы писали:
BFE>Не знаю как вам, а мне часто хочется написать функцию возвращающую код ошибки осмысленным текстом: BFE>... BFE>Идеальным решением для меня было бы такое: BFE>[ccode] BFE>... BFE>Но так по стандарту нельзя. Зато можно внести enum внутрь функции. BFE>... BFE>Тоже самое касается и, например, std::pair, как результата функции. Вечно забываю, где ключ, а где данное. Теперь можно писать:
Полностью согласен, не вижу смысла пытаться запихнуть всё в error_code/pair/tuple и т.п. — обычная структура/enum удобнее.
Разве что бывают случаи где pair/tuple оправданны за счёт того что дают обход полей/операторы сравнения/и т.п., и то это только пока нет compile-time reflection. Либо как промежуточные результаты работы обобщённого/МП кода.
Здравствуйте, Vain, Вы писали:
V>Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком.
Вот ты зануда
для меня, например, трюк — не сталкивался с таким и не подумал, какие горизонты откроет auto в типе возвращаемого значения
Здравствуйте, enji, Вы писали:
V>>Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком. E>Вот ты зануда E>для меня, например, трюк — не сталкивался с таким и не подумал, какие горизонты откроет auto в типе возвращаемого значения
неименованые структуры и раньше можно было тайпдефить, ауто и раньше в разные типы превращалось, — не понятно в чём открытие.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>неименованые структуры и раньше можно было тайпдефить, ауто и раньше в разные типы превращалось, — не понятно в чём открытие.
а при чем тут неименованные структуры? Просто не додумался, что можно вернуть объект локального типа
Здравствуйте, Vain, Вы писали:
V>Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком.
Я рад, что вы так говорите. Значит тут с внешним и внутренним связыванием всё ок? Да?
Здравствуйте, enji, Вы писали:
V>>неименованые структуры и раньше можно было тайпдефить, ауто и раньше в разные типы превращалось, — не понятно в чём открытие. E>а при чем тут неименованные структуры?
именно для них запрет был
E>Просто не додумался, что можно вернуть объект локального типа
а вот это уже трюк, только наоборот
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>>>неименованые структуры и раньше можно было тайпдефить, ауто и раньше в разные типы превращалось, — не понятно в чём открытие. E>>а при чем тут неименованные структуры? V>именно для них запрет был
Где? Не было такого запрета. Был и остаётся запрет на определение типа в описании функции.
Кстати:
auto fun3()
{
struct { int m_a; int m_b; } t;
t.m_a = 1;
t.m_b = 2;
return t;
}
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, Vain, Вы писали:
V>>именно для них запрет был BFE>Где? Не было такого запрета. Был и остаётся запрет на определение типа в описании функции.
Возможно не запрет, а просто проблемы в компиляторах. Сейчас уже не помню, но приходилось добавлять имя чтобы компилировалось нормально.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, B0FEE664, Вы писали:
V>>Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком. BFE>Я рад, что вы так говорите. Значит тут с внешним и внутренним связыванием всё ок? Да?
Не вижу связи, причём здесь это?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, UA, Вы писали:
BFE>>Наконец-то можно возвращать структуры определённые внутри, а не вне функции: UA>Зачем вообще что то объявлять? UA>Делали бы так: UA>
— читать так легче, можно несколько return'ов сделать.
BFE>>return'ов может быть несколько. UA>И что?
То, что типы возвращаемого объекта должны совпадать.
Здравствуйте, Vain, Вы писали:
V>>>Я к тому это, что сообщения с префиксом [trick] здесь пишут, если в коде имеется действительно какой-то трюк или хинт с кодом, чтобы добиться желаемого. Но в приведённом тобой коде я трюков никаких не увидел, зато увидел применение обычного синтаксиса поддерживаемого самим языком. Это не является трюком. BFE>>Я рад, что вы так говорите. Значит тут с внешним и внутренним связыванием всё ок? Да? V>Не вижу связи, причём здесь это?
Смотрите, у структуры st нет связывания:
auto fun3()
{
struct st{ int m_a; int m_b; };
st t;
t.m_a = 1;
t.m_b = 2;
return t;
}
Соответственно вопрос, можно ли использовать результат этой функции в другой единице трансляции?
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>В этом их большАя часть различий (другая часть вытекает из отсутствия compile-time reflection). EP>С именами полей код получается более выразительным, нежели с безликими first/second/get<I>. Всем известный пример — std::map::insert, но там хоть типы разные.
Вот в рамках текущего стандарта мне второе кажется менее важным, чем первое. Ну вернет эта функция нечто, у которой могут быть какие-то именованные поля, а каких-то может не быть. Что мне потом с этим делать? Наличие-отстутствие я проверить не могу. Только явно звать "в надежде на...".
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>>В этом их большАя часть различий (другая часть вытекает из отсутствия compile-time reflection). EP>>С именами полей код получается более выразительным, нежели с безликими first/second/get<I>. Всем известный пример — std::map::insert, но там хоть типы разные. W>Вот в рамках текущего стандарта мне второе кажется менее важным, чем первое.
Ты о чём? О значении first/second в результате insert?
W>Ну вернет эта функция нечто, у которой могут быть какие-то именованные поля, а каких-то может не быть. Что мне потом с этим делать?
Например выбирать по code completion, либо смотреть документацию/исходник.
W>Наличие-отстутствие я проверить не могу.
Почему? Код-то доступен.
W>Только явно звать "в надежде на...".
Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple.
Здравствуйте, Went, Вы писали:
EP>>Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple. W>Я просто не могу представить реального случая, где бы подобный подход мог иметь смысл.
Любая функция конвертации строки в структуру или число.
W>Если это обычная функция, возвращающая, например код ошибки, или результат исполнения, который "не поместился" в скалярный тип, то я не вижу смысла пихать определение структуры вовнутрь ее. За сомнительную экономию нескольких идентификаторов и пунктуаций мы получаем: W>1. Кишки функции наружу.
В каком смысле? То, что определение описано внутри функции, а не снаружи? А typedef key key_type; у std::map — это кишки класса наружу? Нет? Почему?
W>2. Невозможность использовать этот тип где либо еще, объявлять его явно.
Это плюс, а не минус. Это не позволит перепутать результат функции с чем-то ещё.
W>3. Необходимость лезть в реализацию функции для поиска ее возврата.
С кодами int, bool или "не дай бог" errno() легче что-ли?
W>Лучше определить структуру явно в заголовке класса.
Не легче. Это сильно засоряет scope класса бессмысленными типами имеющими отношение только к конкретным функциям.
W>Если же это какое-то значимое данное, состав которого неочевидным образом определяется на момент компиляции тела функции, то без статической рефлексии или замены на туплы, мы просто не будем знать что с ней делать дальше. Поэтому это тоже не вариант. W>Так в каком же случае это полезно?
Например, функция std::stod вместо бросания исключения могла бы возвращать результат, код конвертации и указатель на константную строку с описанием ошибки.
Здравствуйте, Went, Вы писали:
BZ>>в результате получаем просто функцию, возвращающую несколько поименованных результатов. W>Да. Но при этом: W>1. Вынуждены делать функцию инлайн.
Здравствуйте, BulatZiganshin, Вы писали: BZ>и что возвращает функция int fread(...) ? BZ>кол-во прочитанных байт? код ошибки? фазу Луны?
Ну, давайте не заниматься демагогией. Я хотя бы знаю, что это целое. По этому, по названию и сигнатуре функции я в 99% случаев могу предсказать этот результат. Когда вместо int там будет auto, кому-то станет легче? Нет. Потому что даже зная, что она должна вернуть (если функция названа вменяемо, это понятно по одному названию), я должен буду догадаться:
auto bytes_read = fread(...)./*что тут писать, просить помощи у IDE?*/
Это может быть bytes_read, result, bytes, read, length и все другое, что придет в голову разработчику библиотеки.
Признаю, в некоторых случаях это улучшит читаемость кода, но зато затруднит написание практически во всех.
Еще одна радость. Если там можно спросить, например, код ошибки, то использование auto становится уже не удобной мелочью, а назойливой необходимостью:
int bytes_read = fread(...).bytes_read; // Отлично
Но теперь мне нужно узнать о коде ошибки... Значит прошлый код не годится! Будем писать так:
auto result = fread(...);
if (!result.error)
{
int bytes_read = result.bytes_read;
}
Можно еще прописать вариант с errno или возвратом кода ошибки по указателю в последнем параметре, но все эти варианты одинаково уродливы.
Здравствуйте, B0FEE664, Вы писали:
BFE>Соответственно вопрос, можно ли использовать результат этой функции в другой единице трансляции?
а причем здесь результат? это зависит от того как функция объявлена, не?
и вообще, программисту должно быть, вообще, плевать на то как компилятор обеспечит видимость какого-то результата, если он объявил саму функцию видимой.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, Vain, Вы писали:
BFE>>>Наконец-то можно возвращать структуры определённые внутри, а не вне функции: V>>А в чём трюк то заключается?
BFE>Не знаю как вам, а мне часто хочется написать функцию возвращающую код ошибки осмысленным текстом:
BFE>
__>А чем все-таки вас не устраивает первое решение?
Тем, что приходится объявлять enum или структуру с каким-то именем и это имя засоряет пространство имён. Как правило тип возвращаемого значения создаётся ровно для одной функции, тогда логично в качестве имени взять имя функции и добавить в конце слово Result, как в примере выше. Получается слишком длинно, но это ещё можно пережить. А представьте, что у вас в классе 5 методов возвращающих результат. Получается, что в классе объявляется пять enum'ов только для того, чтобы написать пять функций. Код начинает приобретать монструозный вид, особенно для inline методов в две-три строчки. У программиста читающего такой код начинают возникать вопросы к автору относительно его, автора, психического здоровья. Тогда предпринимаются объединить похожие типы результатов в один тип, что привносит в код путаницу на ровном месте. Например, вскоре оказывается, что хотя функция и возвращает в качестве результата некий enum, но, тем не менее, не все значения этого enum'а могут быть возвращены этой функцией, что в вызывающем коде порождает ещё большую путаницу — либо писать обработчик для значения, которое никогда не будет получено, либо заложится на знание устройства функции, что чревато проблемами при изменении функции...
Здравствуйте, Went, Вы писали:
W>>>1. Кишки функции наружу. BFE>>В каком смысле? То, что определение описано внутри функции, а не снаружи? А typedef key key_type; у std::map — это кишки класса наружу? Нет? Почему? W>Нет, в том смысле, что я не могу реализовать функцию отдельно от декларации.
Хм:
extern auto fun();
Хотите сказать, что это не по стандарту?
W>>>2. Невозможность использовать этот тип где либо еще, объявлять его явно. BFE>>Это плюс, а не минус. Это не позволит перепутать результат функции с чем-то ещё. W>Кому не позволит? Разработчику библиотеки?
Пользователю библиотеки.
W>>>3. Необходимость лезть в реализацию функции для поиска ее возврата. BFE>>С кодами int, bool или "не дай бог" errno() легче что-ли? W>Я хотя бы знаю, что эта функция возвращает, глянув только на ее заголовок.
Но это знание вам мало чего даёт. Что толку от того, что функция возвращает, например, bool ? bool GetButtonState() о чём-нибудь говорит?
BFE>>Например, функция std::stod вместо бросания исключения могла бы возвращать результат, код конвертации и указатель на константную строку с описанием ошибки. W>И вместо W>
W>auto number = std::stod("10.0");
W>
W>Писать W>
W>auto number = std::stod("10.0").result;
W>
W>?
Да.
Только вместо auto
const auto&& result = sstd::stod("10.0");
W>Ведь сейчас никто не мешает так делать. Заведи шаблон со всеми требуемыми полями и пиши себе: W>
Здравствуйте, Vain, Вы писали:
BFE>>Соответственно вопрос, можно ли использовать результат этой функции в другой единице трансляции? V>а причем здесь результат? это зависит от того как функция объявлена, не?
Ну и как следует функцию объявить?
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, _hum_, Вы писали:
BFE>>>Не знаю как вам, а мне часто хочется написать функцию возвращающую код ошибки осмысленным текстом:
BFE>>>
__>>А чем все-таки вас не устраивает первое решение?
BFE>Тем, что приходится объявлять enum или структуру с каким-то именем и это имя засоряет пространство имён. Как правило тип возвращаемого значения создаётся ровно для одной функции, тогда логично в качестве имени взять имя функции и добавить в конце слово Result, как в примере выше. Получается слишком длинно, но это ещё можно пережить. А представьте, что у вас в классе 5 методов возвращающих результат. Получается, что в классе объявляется пять enum'ов только для того, чтобы написать пять функций. Код начинает приобретать монструозный вид, особенно для inline методов в две-три строчки. У программиста читающего такой код начинают возникать вопросы к автору относительно его, автора, психического здоровья. Тогда предпринимаются объединить похожие типы результатов в один тип, что привносит в код путаницу на ровном месте. Например, вскоре оказывается, что хотя функция и возвращает в качестве результата некий enum, но, тем не менее, не все значения этого enum'а могут быть возвращены этой функцией, что в вызывающем коде порождает ещё большую путаницу — либо писать обработчик для значения, которое никогда не будет получено, либо заложится на знание устройства функции, что чревато проблемами при изменении функции...
То есть, речь о том, чтобы уметь делать что-то наподобие:
Здравствуйте, B0FEE664, Вы писали:
BFE>>>Соответственно вопрос, можно ли использовать результат этой функции в другой единице трансляции? V>>а причем здесь результат? это зависит от того как функция объявлена, не? BFE>Ну и как следует функцию объявить?
как и раньше наверно — видимой везде.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, _hum_, Вы писали:
__>p.s. а что в таких случаях будет с перегружаемыми функциями, наподобие auto f(); auto f(int i); ?
А проблема то в чём ?
Будут разные типы.
#include <iostream>
#include <type_traits>
using namespace std;
auto f()
{
enum class A { X, Y };
return A::X;
}
auto f(int)
{
enum class A { X, Y };
return A::X;
}
int main()
{
auto fvoid = f();
auto fint = f(1);
cout << is_same<decltype(fvoid), decltype(fint)>::value; // 0
}
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, _hum_, Вы писали:
__>>p.s. а что в таких случаях будет с перегружаемыми функциями, наподобие auto f(); auto f(int i); ?
_NN>А проблема то в чём ? _NN>Будут разные типы.
_NN>
_NN>#include <iostream>
_NN>#include <type_traits>
_NN>using namespace std;
_NN>auto f()
_NN>{
_NN> enum class A { X, Y };
_NN> return A::X;
_NN>}
_NN>auto f(int)
_NN>{
_NN> enum class A { X, Y };
_NN> return A::X;
_NN>}
_NN>int main()
_NN>{
_NN> auto fvoid = f();
_NN> auto fint = f(1);
_NN> cout << is_same<decltype(fvoid), decltype(fint)>::value; // 0
_NN>}
_NN>
Вы немного не так поняли. Я-то думал, что речь о том, чтобы задействовать использование идентификатора функции для идентификации типа возвращаемых ею значений (тем самым экономились бы идентификаторы и в то же время обеспечивалась привязка типа к конкретной функции) — эдакой своеобразной инкапсуляции типа в функцию с возможностью явного экспортирования, то есть некоего аналога
struct f
{
enum class Res{ok, failed};
Res operator()(){return Res::ok;}
};
для которого можно
void main()
{
list<f::Res> ResLog;
for(int i = 0; i < 100; ++i)
{
f::Res res = f()();// а хотелось бы f()
ResLog.push_back(res);
};
}
Однако, как в дальнейшем выяснилось, мой вариант невозможен, ибо идентификация области видимости функции по ее имени не уникальна. А изначальный вариант (и ваш его повторяющий) плох тем, что за пределами функции приходится работать с анонимным типом. Соответственно, например, нельзя просто заранее организовать контейнеры для хранения результатов вычислений функции, не говоря уже о том, что читабельность такого варианта плохая.
Здравствуйте, _hum_, Вы писали:
__>Однако, как в дальнейшем выяснилось, мой вариант невозможен, ибо идентификация области видимости функции по ее имени не уникальна. А изначальный вариант (и ваш его повторяющий) плох тем, что за пределами функции приходится работать с анонимным типом. Соответственно, например, нельзя просто заранее организовать контейнеры для хранения результатов вычислений функции, не говоря уже о том, что читабельность такого варианта плохая.
Ну так на то и анонимные типы.
Нужно больше, нужно создавать именованный тип.
Очень редкая ситуация когда один тип ограничен одной функцией.
Здравствуйте, Erop, Вы писали:
BZ>>в результате получаем просто функцию, возвращающую несколько поименованных результатов E>Неудобно тут то, что имена результатов можно узнать только в теле функции. Удобнее, что бы он были видны в хедере...
А такая функция и будет в header, так как результирующий тип выводится.
__>? __>Если да (хотя автор изначально как-то не совсем то излагал), то согласен, полезная штука.
__>p.s. а что в таких случаях будет с перегружаемыми функциями, наподобие auto f(); auto f(int i); ?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А такая функция и будет в header, так как результирующий тип выводится.
Ну так надо будет ботать код функции, что бы понять чего от ней ждать... В чём профит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Went, Вы писали:
EP>>Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple. W>... W>Если же это какое-то значимое данное, состав которого неочевидным образом определяется на момент компиляции тела функции, то без статической рефлексии или замены на туплы, мы просто не будем знать что с ней делать дальше.
Такая возможность появляется когда мы используем вывод типов в любом виде, не только при возврате значения, но и обычное auto или шаблоны функций.
Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем.
Да даже без вывода типов такая ситуация возможна — сделали статическую трансформацию одной структуры данных в другую, например через Boost.Fusion. Например преобразовали массив структур в структуру массивов — без документации или кода нельзя определить какие поля/методы доступны.
В целом же согласен, не нужно прятать структуру во внутрь функции при каждом подернувшимся случае. Где-то это оправданно, а где-то нет.
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, _hum_, Вы писали:
__>>Однако, как в дальнейшем выяснилось, мой вариант невозможен, ибо идентификация области видимости функции по ее имени не уникальна. А изначальный вариант (и ваш его повторяющий) плох тем, что за пределами функции приходится работать с анонимным типом. Соответственно, например, нельзя просто заранее организовать контейнеры для хранения результатов вычислений функции, не говоря уже о том, что читабельность такого варианта плохая.
_NN>Ну так на то и анонимные типы. _NN>Нужно больше, нужно создавать именованный тип.
_NN>Очень редкая ситуация когда один тип ограничен одной функцией.
да вот и речь о том, что этот редкий случай очень часто встречается — тип кода возврата функции в общем случае специфичный для каждой конкретной функции, и не имеет смысла его использовать отдельно от нее
__>>? __>>Если да (хотя автор изначально как-то не совсем то излагал), то согласен, полезная штука.
__>>p.s. а что в таких случаях будет с перегружаемыми функциями, наподобие auto f(); auto f(int i); ?
E>А что мешает делать как-то так:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Erop, Вы писали:
E>>В чём профит?
EP>Например это как минимум лучше выглядит на стороне пользователя чем при возвращении безликого кортежа. EP>Почему вообще возвращают кортежи (не считая TemplateMP, и случаев где действительно имеет место набор безликих значений) — другой вопрос.
речь же вроде шла о выборе между "засовыванием определения типа в функцию" (и, соответственно, необходимости в этом коде рыться) и "классикой" — использовать независмое определение типа вне тела функции, а не между specific-именоваными и неименоваными компонентами возвращаемых функцией значений.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Went, Вы писали:
EP>>>Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple. W>>... W>>Если же это какое-то значимое данное, состав которого неочевидным образом определяется на момент компиляции тела функции, то без статической рефлексии или замены на туплы, мы просто не будем знать что с ней делать дальше.
EP>Такая возможность появляется когда мы используем вывод типов в любом виде, не только при возврате значения, но и обычное auto или шаблоны функций. EP>Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем.
точно без проблем? ведь известно же: динамические vs статические языки = гибкость vs надежность/безопасность
Здравствуйте, _hum_, Вы писали:
__>1) вызов будет fun::Call(); // а не классический fun();
Ну, зато можно несколько функций сделать при нужде, перегрузками управлять опять же.
Можно, кстати, не struct, а namespace, тогда не надо будет static писать...
__>2) с релизацией такого подхода для метода класса возникнут трудности
Зачем это методам я совсем не понимаю.
__>3) громоздко
что конкретно? То, что надо fun::call писать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
__>>1) вызов будет fun::Call(); // а не классический fun(); E>Ну, зато можно несколько функций сделать при нужде, перегрузками управлять опять же. E>Можно, кстати, не struct, а namespace, тогда не надо будет static писать...
да уж лучше тогда
__>
__>struct f
__>{
__> enum class Res{ok, failed};
__> Res operator()(){return Res::ok;}
__>};
__>
__>для которого можно __>
__>void main()
__>{
__> list<f::Res> ResLog;
__> for(int i = 0; i < 100; ++i)
__> {
__> f::Res res = f()();// а хотелось бы f()
__> ResLog.push_back(res);
__> };
__>}
__>
__>>2) с релизацией такого подхода для метода класса возникнут трудности E>Зачем это методам я совсем не понимаю.
а чем методы хуже? им что не надо возвращать коды ошибок?
__>>3) громоздко E>что конкретно? То, что надо fun::call писать?
нет, писать struct-ы обертки, чтобы реализовать нужный функционал
Здравствуйте, _hum_, Вы писали:
EP>>Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем. __>точно без проблем? ведь известно же: динамические vs статические языки = гибкость vs надежность/безопасность
Это ортогонально дискуссии — в нашем случае есть статические проверки.
Здравствуйте, _hum_, Вы писали:
E>>>В чём профит? EP>>Например это как минимум лучше выглядит на стороне пользователя чем при возвращении безликого кортежа. EP>>Почему вообще возвращают кортежи (не считая TemplateMP, и случаев где действительно имеет место набор безликих значений) — другой вопрос. __>речь же вроде шла о выборе между "засовыванием определения типа в функцию" (и, соответственно, необходимости в этом коде рыться) и "классикой" — использовать независмое определение типа вне тела функции, а не между specific-именоваными и неименоваными компонентами возвращаемых функцией значений.
Я к тому что кортежи используют в том числе в случаях, когда по какой-то причине не хотят выходить за пределы области функции и объявлять что-то вне её. Сейчас в этом же ключе могут использовать локальные структуры.
Здравствуйте, _hum_, Вы писали:
__>да уж лучше тогда
__>>
__>>struct f
__>>{
__>> enum class Res{ok, failed};
__>> Res operator()(){return Res::ok;}
__>>};
__>>
Если таки это больше нравится, то можно и так. Мне это меньше нравится. Например нельзя взять указатель на функцию...
Я бы вообще namespace использовал, а struct тока если в шаблон какой-то передать надо...
E>>Зачем это методам я совсем не понимаю.
__>а чем методы хуже? им что не надо возвращать коды ошибок?
Ну можно же и так писать
enum FunResult { ... };
FunResult fun(...
Для функйий не очень, так как пространство имён забивается, но в нормальных классах таки обычно не так уж много имён...
__>>>3) громоздко E>>что конкретно? То, что надо fun::call писать?
__>нет, писать struct-ы обертки, чтобы реализовать нужный функционал
если честно не понимаю, чем auto fun() так уж сильно отличается... слово auto короче? или в чём фишка?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
BFE>В результате имеем необоснованное ре-использование ResultStatus.
А почему необоснованное?
Мало того, то, что перегрузки совпадают по типу результат, наоборот хорошо как бы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
BFE>>В результате имеем необоснованное ре-использование ResultStatus.
E>А почему необоснованное? E>Мало того, то, что перегрузки совпадают по типу результат, наоборот хорошо как бы...
Потому, что ResultStatus для Call() и Call(int) скорее всего должен быть разный. Например, для Call(int), возможно, надо добавить ResultStatus::WrongCounter с теми же последствиями, что я описал выше.
BFE>Потому, что ResultStatus для Call() и Call(int) скорее всего должен быть разный. Например, для Call(int), возможно, надо добавить ResultStatus::WrongCounter с теми же последствиями, что я описал выше.
IMHO, так делать плохо. Перегруженные функции должны иметь ОДИНАКОВУЮ семантику. Иначе клиентский код превращается в ребус под названием "что он позвал в этом месте???)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
__>>да уж лучше тогда
__>>>
__>>>struct f
__>>>{
__>>> enum class Res{ok, failed};
__>>> Res operator()(){return Res::ok;}
__>>>};
__>>>
E>Если таки это больше нравится, то можно и так. Мне это меньше нравится. Например нельзя взять указатель на функцию... E>Я бы вообще namespace использовал, а struct тока если в шаблон какой-то передать надо...
nаmespace нельзя объявлять внутри класса, а значит, использовать их для методов и статических функций вы не сможете.( да и, имхо, чуждая это языку программирования вещь, а потому, использовать ее надо по минимуму.)
E>>>Зачем это методам я совсем не понимаю.
__>>а чем методы хуже? им что не надо возвращать коды ошибок?
E>Ну можно же и так писать
enum FunResult { ... };
E>FunResult fun(...
E>Для функйий не очень, так как пространство имён забивается, но в нормальных классах таки обычно не так уж много имён...
в системном программировании это сплошь и рядом — когда у каждого метода свой тип возвращаемого кода, и этих методов туева куча.
__>>>>3) громоздко E>>>что конкретно? То, что надо fun::call писать? если честно не понимаю, чем auto fun() так уж сильно отличается... слово auto короче? или в чём фишка?
прежде, чем это писать, надо еще и ручками поработать-понабирать обертки для соответствующих функций. и что хуже всего — эти обертки сопровождаются появлением дополнительного уровня вложенности, а значит, усложняют чтение. сравните:
class CFoo
{
static
auto fun()
{
enum class Res{ok, failed};
//<....>return res;
}
};
и
class CFoo
{
struct fun
{
enum class Res{ok, failed};
static
Res Call()
{
//<....>return res;
}
};
};
а если у вас еще и вложенные классы, то может стать просто нечитаемо.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, _hum_, Вы писали:
EP>>>Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем. __>>точно без проблем? ведь известно же: динамические vs статические языки = гибкость vs надежность/безопасность
EP>Это ортогонально дискуссии — в нашем случае есть статические проверки.
это если падение надежности и безопасности связано только с отсутствием проверки на этапе компиляции, и не связано с ростом количества семантических ошибок самого программиста, пишущего на динамическом языке
Здравствуйте, _hum_, Вы писали:
EP>>>>Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем. __>>>точно без проблем? ведь известно же: динамические vs статические языки = гибкость vs надежность/безопасность EP>>Это ортогонально дискуссии — в нашем случае есть статические проверки. __>это если падение надежности и безопасности связано только с отсутствием проверки на этапе компиляции, и не связано с ростом количества семантических ошибок самого программиста, пишущего на динамическом языке
А что конкретно тогда в динамическом языке такого, что выливается в большее количество ошибок?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, _hum_, Вы писали:
EP>>>>>Либо взять те же языки с динамической типизацией — там возвращаемый тип не виден если не лезть в документацию или в рефлексию, но ведь их используют без проблем. __>>>>точно без проблем? ведь известно же: динамические vs статические языки = гибкость vs надежность/безопасность EP>>>Это ортогонально дискуссии — в нашем случае есть статические проверки. __>>это если падение надежности и безопасности связано только с отсутствием проверки на этапе компиляции, и не связано с ростом количества семантических ошибок самого программиста, пишущего на динамическом языке
EP>А что конкретно тогда в динамическом языке такого, что выливается в большее количество ошибок?
ну, как минимум, зависимость от контекста. программисту сложно отслеживать такие вещи на этапе написания программы, а значит, вероятность того, что он что-то неверно понял или не предусмотрел — выше.