Здравствуйте, Went, Вы писали:
UA>>>>Делали бы так... W>>>Для этого есть туплы. EP>>У их полей нет имён. W>Само собой.
В этом их большАя часть различий (другая часть вытекает из отсутствия compile-time reflection).
С именами полей код получается более выразительным, нежели с безликими first/second/get<I>. Всем известный пример — std::map::insert, но там хоть типы разные.
— читать так легче, можно несколько 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.
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>Не пойму, то есть ты за то чтобы в этом случае auto вообще не использовать? Тогда это ортогонально struct vs tuple.
Я просто не могу представить реального случая, где бы подобный подход мог иметь смысл.
Если это обычная функция, возвращающая, например код ошибки, или результат исполнения, который "не поместился" в скалярный тип, то я не вижу смысла пихать определение структуры вовнутрь ее. За сомнительную экономию нескольких идентификаторов и пунктуаций мы получаем:
1. Кишки функции наружу.
2. Невозможность использовать этот тип где либо еще, объявлять его явно.
3. Необходимость лезть в реализацию функции для поиска ее возврата.
Лучше определить структуру явно в заголовке класса.
Если же это какое-то значимое данное, состав которого неочевидным образом определяется на момент компиляции тела функции, то без статической рефлексии или замены на туплы, мы просто не будем знать что с ней делать дальше. Поэтому это тоже не вариант.
Так в каком же случае это полезно?
Здравствуйте, BulatZiganshin, Вы писали: BZ>в результате получаем просто функцию, возвращающую несколько поименованных результатов.
Да. Но при этом:
1. Вынуждены делать функцию инлайн.
2. Не сможем заменить функцию на виртуальную.
3. Не сможем объединить возвращаемый тип с подобными функциями (тут просто просится какой-то struct read_result;).
4. Ограничены одной точкой выхода.
5. Можем получить неочевидые проблемы с выводимыми типами переменных-членов этой структуры.
Но. Опять же — это все до тех пор, пока нет статической рефлексии. Как только оная появится, ценность подобных записей заметно увеличится, и их существование будет оправдано.
Здравствуйте, 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. Вынуждены делать функцию инлайн.
Здравствуйте, B0FEE664, Вы писали: BFE>Зачем?
Ну, не inline, а делать потроха функции видимыми снаружи.
// Вместо:class X
{
struct Restult {...};
Result some_function();
}
// Делать:class X
{
auto some_function()
{
// А тут что-то, что требует 100500 заголовков...return {...};
}
}
Нет, я не спорю, любая возможность хороша, есть анонимные функции, будут анонимные классы. Просто ценность такого нововведения для меня сомнительна.
Здравствуйте, 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;
?
Ведь сейчас никто не мешает так делать. Заведи шаблон со всеми требуемыми полями и пиши себе:
Здравствуйте, Went, Вы писали:
W>>>3. Необходимость лезть в реализацию функции для поиска ее возврата. BFE>>С кодами int, bool или "не дай бог" errno() легче что-ли? W>Я хотя бы знаю, что эта функция возвращает, глянув только на ее заголовок.
Здравствуйте, 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 или возвратом кода ошибки по указателю в последнем параметре, но все эти варианты одинаково уродливы.