Skip to content

Conversation

@Microvenator
Copy link
Contributor

No description provided.

w
```

Символьный тип `char` является целочисленным, поэтому может выступать в качестве базового для перечисления. В этом примере мы вызвали появившуюся в C++23 функцию [std::to_underlying()](https://en.cppreference.com/w/cpp/utility/to_underlying.html). Она приводит значение перечисления к базовому типу. До C++23 с той же целью приходилось выполнять явное приведение типов через `static_cast`:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Надо бы пояснить зачем нужен std::to_underlying(), в чем его преимущество над кастом. Например для использования в обобщенном коде:

import std; enum ServerState { down, starting, ready, stopping }; enum HttpPort : std::uint16_t { def = 80, tls = 443 }; template <class T> void pint_enum_value(std::string name, T value) { std::println("{}: {}", name, std::to_underlying(value)); } int main() { pint_enum_value("down", ServerState::down); pint_enum_value("ready", ServerState::ready); pint_enum_value("tls", HttpPort::tls); }

Также, если кто-то изменит базовы тип на больший, то не будет опасного сужающего преобразования.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово


int main()
{
const char level = std::to_underlying(LogLevel::Info);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В этой строчке явно указан результирующий тип, что несколько понижает ценность задачи. Кроме того человека невнимательного (вроде меня) может сбить с толку, что изначально работаем со значением перечисления. Если не быть внимательным, то ожидаешь вывод конкретного значение. А sizeof замыливается.

Предлагаю сначала рассказать о std::underlying_type_t и в примере использовать его:

import std; enum class LogLevel : char { Trace, Debug, Info, Warn, Error }; int main() { std::println("{}", sizeof(std::underlying_type_t<LogLevel>)); }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Заменила задачу на другую.

true
```

Реализуйте функцию `sum_if()`, которая принимает два параметра. Перый — это словарь `std::map` с ключами - строками и значениями типа `std::size_t`. Второй параметр - функция-предикат, принимающая строку и возвращающая `bool`. Функция `sum_if()` должна вернуть сумму значений элементов словаря, для ключей которых предикат возвращает `true`. {.task_text}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ИМХО, условие задачи выглядит скомканным. Лучше написать про параметры функции с указанием полных типов, а потом в отдельных предложениях рассказать про каждый параметр.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переформулировала условие. Хочется, чтобы пользователь по описанию сам осилил составить типы параметров.


return res;
}
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ИМХО, после задачи стоит добавить, что тоже самое можно сделать с помощью стандартных алгоритмов. Например: c помощью std::accumulate():

import std; using dict_t = std::map<std::string, std::size_t>; std::size_t add_if(std::size_t sum, dict_t::value_type item) { return item.first.empty() ? sum : sum + item.second; } int main() { dict_t dict {{"01", 100}, {"03", 20}, {"", 1000}, {"05", 5}, {"", 2200}, {"", 1}, {"10",3}}; const std::size_t sum = std::accumulate(dict.begin(), dict.end(), 0, add_if); std::println("sum: {}", sum); }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Скорректировала условие задачи. Добавила про accumulate() в него.


Классы — это более сложные абстракции, чем фундаментальные типы:
- Фундаментальные типы максимально близки к аппаратному представлению чисел. Переменная фундаментального типа — это всего лишь небольшая область памяти, которую компилятор трактует определенным образом. Большинство операций над фундаментальными типами сводится к единственной машинной команде.
- Классы же имеют конструктор и деструктор. Их поля могут находиться в разных участках памяти. Для чтения и записи полей могут быть реализованы методы произвольной сложности.
Copy link
Collaborator

@khva khva Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Их поля могут находиться в разных участках памяти.

Это некорректное утверждение. Все поля экземпляра класса располагаются в единой области памяти. Другое дело, что поля могут указывать на другие области динамической памяти, и управление этой памятью скрыто за фасадом класса.

Нужно переформулировать это предложение и возможно стоит пояснить на примере. Можно взять std::vector<> и рассказать, что поля вектора лежат в одном фрагменте памяти, а массив элементов в другом.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переформулировала эту часть.

public:
explicit File(std::vector<Section> sections);
std::size_t sections_count();
std::pair<Section, std::size_t> findSection(std::function<bool(Section s, std::size_t idx)>);
Copy link
Collaborator

@khva khva Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Наверное, лучше так:

std::pair<Section, std::size_t> findSection(std::function<bool(Section, std::size_t)> pred);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


Перед вами класс `File`, хранящий секции файла некоего формата. {.task_text}

Добавьте в объявление класса метод `findSection()`. Он принимает объект `std::function` с аргументом шаблона — типом функции-предиката. Она в свою очередь принимает два параметра: секцию `Section` и индекс секции `std::size_t`. Функция `findSection()` возвращает пару: первую секцию файла\, для которой предикат вернул `true`, и ее индекс. Если такой секции нет, функция возвращает пустую секцию и индекс, равный `std::numeric_limits<std::size_t>::max()`. {.task_text}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ИМХО, скомкано и сложно для понимания. Проще взглянуть на определение функции и так понять, что нужно сделать. Предлагаю сначала сказать про входной параметер и выходное значение, а потом в отдельных предложения описать их. Также можно ввести дополнительные типы и ссылаться на них:

struct Section { std::string header; std::string name; std::string contents; }; using FindPred = bool(Section, std::size_t); using FindRes = std::pair<Section, std::size_t>; ...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переформулировала

Так выглядит инициализация единицами массива из тысячи элементов:

```cpp
int offsets[1000] = {1};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это неверно:

import std; int main() { // будет заполнен только 1-ый элемент int arr1[4] = {1}; std::println("arr1: {}", arr1); // будут заполнены все элементы int arr2[4] = {}; std::fill(std::begin(arr2), std::end(arr2), 2); std::println("arr2: {}", arr2); }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, опечаталась. В предыдущем предложении же именно это и говорилось. Добавила задачу.

float samples[3] = {4.5, 2.0, -1.1};
```

Если длина списка инициализации меньше длины массива, оставшиеся элементы заполняются нулями (даже если 0 не является корректным значением для типа).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Предлагаю также пояснить как заполнять массив деволтными значениями:

int arr[16] = {}; int arr[16] {};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово.

};

// ...
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Секция Классы и структуры оставляет странное впечатление. Кажется ничего нового не было рассказано. А зачем тогда она?

Нужно добавить что-то связаное с типами либо какое-то послесловие.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С твоим комментом выше она получилась чуть более подробной.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants