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

164
25 августа 2018, 06:40

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

Answer 1

Эти переменные-теги и соответствующие им типы предназначены для решения следующей задачи.

Пусть у меня есть

std::variant<std::string, const char *> v;

и я решил инициализировать эту переменную как

std::variant<std::string, const char *> v("Hello World");

Правила инициализации std::variant совпадают с правилами overload resolution (для некоей воображаемой функции). Эти правила говорят, что я в этом случае получу вариант, хранящий const char *. Но вдруг мне по какой-то причине нужно, чтобы литерал "Hello World" использовался именно как инициализатор для варианта, хранящего std::string.

Вот для достижения этой цели я и могу использовать std::in_place_type с шаблонным аргументом соответствующего типа

std::variant<std::string, const char *> v(std::in_place_type<std::string>, "Hello World");

std::in_place_type<std::string> в этом случае - это "фиктивный" тег-аргумент, задача которого - просто заставить компилятор выбрать правильный конструктор в процессе разрешения перегрузок (overload resolution). Больше этот аргумент ничего не делает.

std::in_place_index делает то же самое, только выбирая тип по порядковому индексу в списке шаблонных параметров std::variant

std::variant<std::string, const char *> v(std::in_place_index<0>, "Hello World");

Пользуясь этим тегами я могу делать forwarding аргументов в любой конструктор std::string, в том числе многоаргументный

std::variant<std::string, const char *> v(std::in_place_type<std::string>, 10, 'a');
// Создает внутренний `std::string(10, 'a')`

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

std::variant<std::string, const char *> 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 не имеет никаких шаблонных параметров, т.е. является обычной переменной, а не шаблоном переменной.

READ ALSO
Как прилинковать нестандартную версию protobuf используя cmake

Как прилинковать нестандартную версию protobuf используя cmake

Есть проект под arm который компилируется и собирается на х86ой машине (кросскомпиляция)Есть версия библиотеки protobuf собранная под arm по этой...

191
Не мапится объект из POST запроса

Не мапится объект из POST запроса

Моя задача состоит в том, чтобы создать post запрос, получить из него объект Item и сохранить его в базу данных OracleДля эмуляции запроса я использую...

352
File is read-only. Правка файла в библиотеке мавена

File is read-only. Правка файла в библиотеке мавена

Процесс отладки показывает, что вызов с фронта обрабатывается классами из external libraries в maven

182
автоматизация java selenium webdriver

автоматизация java selenium webdriver

после запуска, открывается страница с хромом, в поле куда должны вписываться символы отget(), написано "data:,"

291