Pull to refresh

Comments 47

Почему вы не стали использовать пользовательские литералы вместо страшного make_static_string?

А почему написали свой велосипед, а не использовали, например, boost::hana?

Ну, хотя бы в образовательных целях
Я конечно же подозревал, что кто-то уже сделал нечто подобное

Возможно ли такие строки определять в шаблонных параметрах?

Нет, но можно например использовать такой workaround с помощью хэшей:


template<unsigned long long> constexpr auto greet() {return "Hello, guest!";}
template<> constexpr auto greet<static_string_hash("alice")>() {return "Hello, Alice!";}
template<> constexpr auto greet<static_string_hash("bob")>() {return "Hello, Bob!";}

constexpr auto name = make_static_string("alice");
constexpr auto greeting = greet<name.hash()>();
std::cout << greeting << std::endl;
Не очень понял где тут хэш и как достать саму строку из щаблонного параметра?

Прошу прощения, прочитал "определять" как "передавать"
В C++ известная проблема со строковыми литералами в шаблонных параметрах, поэтому если так хочется именно в шаблонных параметрах, то придется определять строку как список символов, например так:


template<char ... Chars> struct static_string{};

template<char ... Chars1, char ... Chars2>
constexpr auto static_string_concat(
const static_string<Chars1 ... >& str1,
const static_string<Chars2 ... >& str2) {
    return static_string<Chars1 ..., Chars2 ...>{};
}

template<char ch, char ... Chars>
std::ostream& operator<<(std::ostream& os, const static_string<ch, Chars ...>& str) {
    os << ch << static_string<Chars ... >{};
    return os;
}

std::ostream& operator<<(std::ostream& os, const static_string<>& str) {
    return os;
}

constexpr static_string<'a', 'b', 'c'> str1;
constexpr static_string<'d', 'e', 'f'> str2;
constexpr auto str = static_string_concat(str1, str2);
std::cout << str << std::endl;

Честно говоря, этот вариант я тоже рассматривал, но в итоге ничего толкового из него не вышло

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

Все-таки возможно сделать этот вариант хорошо с помощью оператора пользовательского литерала:


template<typename Char, Char ... Chars>
constexpr static_string<Char, Chars ... > operator"" _ss() {
    return static_string<Char, Chars ... >{};
};

constexpr auto str1 = "abc"_ss;
constexpr auto str2 = "def"_ss;
constexpr auto str = str1 + str2 + str1;
std::cout << str << std::endl;

Пожалуй, вынесу это в статью

Пользовательские литералы и без шаблона могут взять строку:
constexpr MyType operator "" _ss(const char* str, const size_t size)
{
// ...
}
Вместо имен вида static_string_concat было бы наверное красивее создать отдельный неймспейс в стиле static_string::concat
Тип символов вынести в шаблонный параметр для поддержки wchat_t
Нехорошо, что Ваш тип struct static_string, с интерфейсом, похожим на std::string, в отличие от последнего имеет функции
    constexpr size_t length() const {
        return Size - 1;
    }
    constexpr size_t size() const {
        return Size;
    }
, возвращающие разные значения, что может приводить к множеству ошибок.

Согласен, заменю на sizeof

В то время как rust научился проверять валидность sql запросов на этапе компиляции, в цпп не могут проинициализировать и сложить 2 строчки без UB и рулонов кода.
А Rust уже научился автоматически конвертировать существующий C++ный код в код на Rust-е? Ну вот чтобы не нужно было сопровождать мегатонны унаследованного C++ного кода, который, сюрпраз-сюрпрайз, работает и приносит деньги. И чтобы не нужно было этот код вручную с нуля на Rust переписывать. А просто запустил волшебный тул и получил вместо копролитов мамонта на C++ свежий и благоухающий фиалками код на Rust-е.
подозреваю, что это невозможно. Возможна только обратная конвертация.

Давайте ссылку на вашу проверку кода в языке.

UFO landed and left these words here
А чем джойны в where-условии delete отличаются от джойнов в where-условии select или update?
UFO landed and left these words here

Голову пеплом посыпал, спасибо

Почему нельзя решить проблему с помощью препроцессора? Некрасиво???

Нет, не забыл. Действительно очень похоже.

>порядок инициализации глобальных объектов не определен

Это почему это? Можно заставить компилятор инициализировать глобальные переменные в определенном порядке.
Для GCC это init_priority
Для VC++ #pragma init_seg

В стандарте не определен насколько я помню, init_priority и #pragma init_seg это фишки отдельных компиляторов

UFO landed and left these words here
а для чего это надо то
auto str = «hello» + «world»;
если можно сразу написать
auto str = «helloworld»;
т.е. просто в какой момент получается что всё статично, но при этом не совсем? как?

В статье есть пример с плагинами, есть директория с плагинами path = "/path/to/plugins/" и два плагина plugin1 = "plugin1.so", plugin2 = "plugin2". Чтобы не писать два раза путь так plugin1_path = "/path/to/plugins/plugin1" и plugin2_path = "/path/to/plugins/plugin2" мы используем конкатенацию plugin1_path = path + "plugin1" и plugin2_path = path + "plugin2"
Да, все полностью статично, то есть конкатенация происходит на этапе компиляции

#define path "/path/to/plugins/"
#define plugin1_path path «plugin1»
#define plugin2_path path «plugin2»
Не?

Как вариант, правда я не уверен, что все операции со строками, которые описаны в статье, возможно реализовать на макросах

Мня опередили по макросам )
Путь до плагина сколько раз в программе используется? Один раз при запуске? Это экономия на спичках, мне кажется, и приведет она не только к захламлению кода но и к чему то типа «стоимость товара: один рубля»…

P.S. Была книга 10 лет назад по шаблонам где человек считает таким методом чуть ли не интегралы, а результат программы лишь вывод окончательного результата. Но тема так и не пошла )) И кстати, Intellisense какбы не повесился.

Если у Вас в проекте это не дает большого выигрыша, то конечно, не следует это использовать. Я уверен, в большинстве случаев constexpr char[] будет достаточно.
P.S. А в Nvidia, например, используют compile-time хэш таблицу
https://www.youtube.com/watch?v=kUbWYdlS9v0&list=PLZN9ZGiWZoZoFa2q0NqD6metQxavT2JYP&index=19

Да я не говорю что это плохо, спасибо, на самом деле очень интересно было посмотреть на результат. Уверяю Вас, сейчас компьютеры очень не тупые и «молотят» так, что иногда удивляешься. Я тут недавно делал проект OpenGL с 2д физикой сурьезной, 300-400тел, и сам не понимал в начале реально ли, потянет ли современный комп. Короче, в результате получил 500-600фпс вместе с отрисовкой, и понял какая это мощь… Видели бы вы эти расчеты… После этого конкатенация строк выглядит как шутка

char потом нужно будет преобразовать в string в runtime. А воще смешивать string и char это потенциальный выстрел в ногу.

И тут на помощь приходит string_view. Только вместо const char* надо auto для начала

Обновил статью с учетом замечаний

Ну, тогда докину еще одно ;)
КМК путь к директории может быть записан и без разделителя в конце. Если кто-то не сильно внимательный исправит PLUGIN_PATH вот так:


const std::string PLUGIN_PATH = "/usr/local/lib/project/plugins";

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

Добавил альтернативный вариант реализации статических строк

Sign up to leave a comment.

Articles