simstr 1.6.1
Yet another strings library
 
Загрузка...
Поиск...
Не найдено
Конвертация типов в в строковые выражения

Различные способы конвертации типов в строковые выражения. Если вы реализуете один (и только один) из способов преобразования вашего типа в строковое выражение, то сможете использовать ваш тип напрямую в операциях конкатенации со строковыми выражениями и как аргументы в функциях e_concat и e_subst.

Способ 1

Просто реализуйте в своём типе требования, чтобы он являлся строковым выражением.

Пример:
struct add_exclamation {
ssa text_;
unsigned count_;
// symb_type
using symb_type = char;
// length
size_t length() const noexcept {
return text_.length() + count_;
}
// place
char* place(char* ptr) const noexcept{
ptr = text_.place(ptr);
std::char_traits<char>::assign(ptr, count_, '!');
return ptr + count_;
}
};
TEST(ToStrExpr, CheckExclamation) {
std::string test = "Msg is <" + add_exclamation{"Happy Birthday", 5} + ">";
EXPECT_EQ(test, "Msg is <Happy Birthday!!!!!>");
add_exclamation msg{"Happy Birthday", 3};
test = e_concat("", "Msg is <", msg, ">");
EXPECT_EQ(test, "Msg is <Happy Birthday!!!>");
const add_exclamation cmsg{"Happy Birthday", 0};
test = e_subst(S_FRM("Msg is <{}>"), cmsg);
EXPECT_EQ(test, "Msg is <Happy Birthday>");
}

Способ 2

Создайте тип-обёртку, который является строковым выражением и может инициализироваться вашим типом. После задайте их соответствие с помощью специализации шаблона convert_to_strexpr.

Пример:
// Тип / Type
struct car_info {
std::string model;
int year;
};
// Обёртка для превращения его в строковое выражение
// Wrapper to turn it into a string expression
struct car_info_expr {
const car_info& car_;
expr_num<char, int> year;
car_info_expr(const car_info& car) : car_(car), year(car.year){}
inline static constexpr ssa ModelTag = "Model: ";
inline static constexpr ssa YearTag = ", Year: ";
using symb_type = char;
size_t length() const {
return ModelTag.length() + car_.model.length() + YearTag.length() + year.length();
}
char* place(char* ptr) const {
ptr = ModelTag.place(ptr);
std::char_traits<char>::copy(ptr, car_.model.data(), car_.model.length());
ptr += car_.model.length();
ptr = YearTag.place(ptr);
return year.place(ptr);
}
};
} // namespace simstr::tests
namespace simstr {
// Специализируем шаблон, задавая соответствие типа и его обёртки
// Specialize the template by specifying a match between the type and its wrapper
template<>
struct convert_to_strexpr<char, tests::car_info> {
// Указываем тип, который будет "обёрткой" для нашего типа
// Specify the type that will be a "wrapper" for our type
using type = tests::car_info_expr;
};
} // namespace simstr
namespace simstr::tests {
TEST(ToStrExpr, CheckCarInfo) {
car_info ci{"Ford", 2020};
std::string test = "Car is <"_ss + ci + ">";
EXPECT_EQ(test, "Car is <Model: Ford, Year: 2020>");
ci.year++;
test = e_concat("", "Car is <", ci, ">");
EXPECT_EQ(test, "Car is <Model: Ford, Year: 2021>");
ci.year++;
test = e_subst(S_FRM("Car is <{}>"), ci);
EXPECT_EQ(test, "Car is <Model: Ford, Year: 2022>");
}

Способ 3

Специализируйте шаблон convert_to_strexpr для вашего типа и создайте в нём статическую функцию convert, принимающую ваш объект и возвращающую строковое выражение, строковый объект simstr или std::basic_string.

Пример:
struct animal {
std::string name_;
std::string sound_;
};
} //namespace simstr::tests
namespace simstr {
// Специализируем шаблон, задавая соответствие типа и его обёртки
// Specialize the template by specifying a match between the type and its wrapper
template<>
struct convert_to_strexpr<char, tests::animal> {
// Создаём функцию `convert`, которая вернёт строковое представление объекта
// Create a function `convert`, that will return a string representation of the object
static auto convert(const tests::animal& a) {
// Так делать нельзя - операция + складывает в выражение ссылки на временные объекты,
// которые разрушаются после ";", и возвращать такой объект нельзя.
// This can't be done - the operator+ adds references to temporary objects to the expression,
// which are destroyed after ";", and such an object cannot be returned.
//return "Animal: " + a.name_ + ", Sound: " + a.sound_;
// А вот такой можно - он не хранит ссылки на временные объекты
// But this one is possible - it doesn't store references to temporary objects
return e_concat("", "Animal: ", a.name_, ", Sound: ", a.sound_);
// Также можно возвращать просто std::string, stringa, lstringa
// You can also return just std::string, stringa, lstringa
}
};
} //namespace simstr
namespace simstr::tests {
TEST(ToStrExpr, CheckAnimal) {
animal cat{"Cat", "Meow"};
std::string test = "<"_ss + cat + ">";
EXPECT_EQ(test, "<Animal: Cat, Sound: Meow>");
const animal dog{"Dog", "Woof"};
test = e_concat("", "<", dog, ">");
EXPECT_EQ(test, "<Animal: Dog, Sound: Woof>");
test = e_subst(S_FRM("\\_{}_/"), animal{"Snake", "Pssstt"});
EXPECT_EQ(test, "\\_Animal: Snake, Sound: Pssstt_/");
}

Способ 4

Просто в своём типе сделайте функцию template<typename K> auto to_strexpr()const, которая возвращает строковое выражение или строковый объект.

Пример:
struct test {
int number;
int from;
// Сделаем две отдельные реализации: для char (попроще) и для остальных типов (там придётся возвращать не литералы, а simple_str, и требуется копия)
// Let's make two separate implementations: for char (simpler) and for other types (there we'll have to return not literals, but simple_str, and a copy is required)
template<typename K> requires (std::is_same_v<K, char>)
auto to_strexpr() const {
return e_concat("", "test ", number, " from ", from);
}
template<typename K> requires (!std::is_same_v<K, char>)
auto to_strexpr() const {
// uni_string возвращает локальный объект, а ссылку на них нельзя возвращать из функции,
// поэтому в e_concat надо форсировать сохранение по копии, а не по ссылке.
// uni_string returns a local object, and references to them cannot be returned from a function,
// so in e_concat we need to force saving by copy, not by reference.
return e_concat(force_copy{empty_expr<K>{}}, force_copy{uni_string(K, "test ")}, number, force_copy{uni_string(K, " from ")}, from);
}
};
TEST(ToStrExpr, CheckTest) {
test t1{1, 10};
std::string t = "Begin <"_ss + t1 + ">";
EXPECT_EQ(t, "Begin <test 1 from 10>");
const test t2{8, 12};
t = e_concat("", "<", t2, ">");
EXPECT_EQ(t, "<test 8 from 12>");
t = e_subst(S_FRM("<{}>"), test{99, 100});
EXPECT_EQ(t, "<test 99 from 100>");
// Проверим работу для не char
// Let's check the work for non-char
std::wstring wt = L"aaa "_ss + test{99, 100};
EXPECT_EQ(wt, L"aaa test 99 from 100");
std::u16string ut = u"aaa "_ss + test{99, 100};
EXPECT_EQ(ut, u"aaa test 99 from 100");
}