cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

std::format - позволить указывать переменные для подстановки прямо внутри строки #461

Open Aegel5 opened 3 years ago

Aegel5 commented 3 years ago

Такой формат уже реализован в С#, пример:

int a = 10;
int b = 20;
var res = $"Vars: a={a}, b={b}!";

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

Как конкретно реализовать это в С++ я не знаю, возможно тоже добавить $ перед строкой:

int a = 10;
int b = 20;
auto res = $"Vars: a={a}, b={b}!";
GeorgyFirsov commented 3 years ago

Для этого в языке должна существовать возможность доступа к таблице идентификаторов. Насколько мне известно, такое предполагается пропозалом по рефлексии. Если не предполагается, то поправьте 😄

incoder1 commented 2 years ago

В С++ есть разные типы данных, и нет такого что все типы - классы унаследованные от общего предка и имеют метод преобразования в строку, на чем в общем и базируется трюки из $"Vars: a={a}, b={b}!" Python, Ruby, Groovy и т.д. В этих языках однозанчно можно сказать что у любого типа есть метод преобразующий его в строку. C++ язык другого уровня контроля абстракций, за счет чего на нем можно написать как ядро операционной системы так и прикладную CRUD программу. Поэтому типы можно создавать разные: структуры, массивы объединения, перечисления и т.д. И к строке они в общем могут приводится по усмотрению программиста, по умолчанию этого не происходит. Исходную проблему так же можно решить через библиотеки, например Boost Format

Aegel5 commented 2 years ago

Речь идет исключительно о синтаксическом сахаре.

Если такое работает: std::cout << std::format("Hello {}!\n", 123); то значит должно работать и такое std::cout << $"Hello {123}!\n";

incoder1 commented 2 years ago

std::format это шаблонная функция. Она использует синтаксис языка, а не втраиваетсья в него. А значит и не заставляет обязательно линковать стандартную библиотеку к любой программе или библиотеке. И не влияет на оптимизатор кода. В случае с синтаксисом - так уже не получится и выходит что на С++ уже нельзя писать embedded, ядра операционных систем, драйвера устройств и т.д. (да dynamic_cast, typed и static переменные - это явно промах который привел к разделению стандартной библиотеки на части, одна из которых это ABI). Посмотрите другие компилируемые языки, вы в них не найдете такой возможности, в отличие от интерпретаторов где такой синтаксис - стандарт.

Aegel5 commented 2 years ago

А как насчет суффиксов для строк? auto s = "abc"s; Суффиксы - это новая возможность языка. При этом не мешают писать embedded, ядра операционных систем, драйвера устройств и т.д. Просто если нет определенных include, то программа не будет компилироваться. Так и тут сделать: если определена функция std::format - вызываем ее, если нет - ошибка.

unterumarmung commented 2 years ago

@alexzh2, вы не правы. Во-первых, это называется user-defined literals. Во-вторых, это user-defined literals - это механизм языка С++: https://en.cppreference.com/w/cpp/language/user_literal В-третьих, литералы для std::string и других библиотечных типов являются частью стандартной библиотеки языка С++: https://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s. Они были даже добавлены в следующем стандарте после добавления user-defined literals как механизма языка.

oficsu commented 2 years ago

Возьмём ваш пример:

int a = 10;
int b = 20;
auto res = $"Vars: a={a}, b={b}!";

Когда я захочу поменять тип a с int на Foo, откуда компилятор узнает, как преобразовать экземпляр Foo в строку? Нам потребуется решение проблемы. И эта проблема принципиально не имеет универсального решения на текущий момент

Проблема здесь даже не в классе Foo, который мы не умеем преобразовывать — мы можем найти с десяток некрасивых решений. Есть другая, нерешаемая проблема — в самой строке. У нас есть std::string, char const* и, например, сторонние folly::fbstring и QString. Дело в том, что часто пользователи хотят в контексте каждого типа строки иметь различный алгоритм преобразования, учитывающий кодировку, ширину символа или даже выбирать другое текстовое представление в зависимости от дальнейшего использования этой строки. Проблема в том, что строковый литерал не знает, к какой из строк будет преобразован в будущем, а значит, не сможет выбирать способ форматирования, основываясь на целевом типе строки:

std::string x = $"Vars: a={a}, b={b}!";
folly::fbstring y = $"Vars: a={a}, b={b}!";
QString x = $"Vars: a={a}, b={b}!";

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