Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Разъясните смысл std::in_place, std::in_place_type и std::in_place_index для std::optional, std::variant и std::any

#cpp #cpp17


С какой целью std::in_place, std::in_place_type и std::in_place_index используются
для std::optional, std::variant и std::any? Каков принцип их работы? Если можно, с
примерами.
    


Ответы

Ответ 1



Эти переменные-теги и соответствующие им типы предназначены для решения следующей задачи. Пусть у меня есть std::variant v; и я решил инициализировать эту переменную как std::variant v("Hello World"); Правила инициализации std::variant совпадают с правилами overload resolution (для некоей воображаемой функции). Эти правила говорят, что я в этом случае получу вариант, хранящий const char *. Но вдруг мне по какой-то причине нужно, чтобы литерал "Hello World" использовался именно как инициализатор для варианта, хранящего std::string. Вот для достижения этой цели я и могу использовать std::in_place_type с шаблонным аргументом соответствующего типа std::variant v(std::in_place_type, "Hello World"); std::in_place_type в этом случае - это "фиктивный" тег-аргумент, задача которого - просто заставить компилятор выбрать правильный конструктор в процессе разрешения перегрузок (overload resolution). Больше этот аргумент ничего не делает. std::in_place_index делает то же самое, только выбирая тип по порядковому индексу в списке шаблонных параметров std::variant std::variant v(std::in_place_index<0>, "Hello World"); Пользуясь этим тегами я могу делать forwarding аргументов в любой конструктор std::string, в том числе многоаргументный std::variant v(std::in_place_type, 10, 'a'); // Создает внутренний `std::string(10, 'a')` Вы можете заметить, что того же эффекта я мог достичь, вручную сначала сконструировав временный объект std::variant v(std::string("Hello World")); но эта версия действительно сначала создает временный объект std::string("Hello World"), а затем перемещает его во внутренний объект std::variant. Это не всегда то, что нужно. Идея с std::in_place_type (и компанией) заключается в том, чтобы получить forwarding передаваемых аргументов прямо в конструктор создаваемого внутреннего объекта, без формирования каких-либо промежуточных временных объектов. std::in_place_type также применим с std::any для явного указания типа хранимого объекта и c той же целью получения forwarding: сконструировать внутренний объект сразу, через forwarding аргументов, без промежуточного перемещения. std::in_place предназначен для использования с std::optional и тоже вызывает именно forwarding последующих аргументов прямо во внутренний конструируемый объект. В std::optional выбирать тип не нужно, ибо он зафиксирован заранее, поэтому std::in_place не имеет никаких шаблонных параметров, т.е. является обычной переменной, а не шаблоном переменной.

Комментариев нет:

Отправить комментарий