Когда я должен использовать std::any
Начиная с C++17 std::any
вводится. Теперь можно написать код, подобный этому
#include <iostream>
#include <any>
#include <string>
int main () {
const double d = 1.2;
std::any var = d;
const std::string str = "Hello World";
var = str;
}
Двойной присваивается переменной var
и чем std::string
был назначен на это.
Почему имеет std::any
был введен?
Я думаю, что это нарушает least astonishment rule
потому что мне трудно думать о ситуации, когда это можно использовать для более ясного выражения того, что мне нравится выражать.
Может ли кто-нибудь дать мне хороший пример, когда std::any
это выгодно.
4 ответа
Когда использовать
void*
как крайне небезопасный шаблон с некоторыми ограниченными случаями использования, std::any
добавляет безопасность типов, и поэтому у него есть реальные варианты использования.
Некоторые возможности:
- В библиотеках - когда тип библиотеки должен содержать или передавать что-либо, не зная набора доступных типов.
- Парсинг файлов - если вы действительно не можете указать, какие типы поддерживаются.
- Передача сообщений.
- Привязки со скриптовым языком.
- Реализация переводчика для языка сценариев
- Пользовательский интерфейс - элементы управления могут содержать что угодно
- Сущности в редакторе
( ссылка)
Я бы назвал это классическим "используйте, когда вы не можете избежать этого".
Я могу думать только о не критичных к производительности реализациях языков сценариев с динамической типизацией, чтобы представлять переменные из мира сценариев, но даже это с натяжкой ( https://www.boost.org/doc/libs/1_68_0/libs/spirit/example/qi/compiler_tutorial/ делает это как для парсера, так и для во время выполнения).
Для всего остального, от парсеров (например, Boost.Spirit.X3) до библиотечных API (например, ASIO), обычно существует более быстрая / лучшая / более конкретная альтернатива, поскольку очень немногие вещи на самом деле являются "чем угодно", большинство из них более конкретны, чем это.,
std::variant
и / илиstd::optional
для "почти любой стоимости"std::packaged_task
/std::function
+ лямбда-выражения для "обратного вызова с аргументами", что было бы в случаеvoid*
в C API.- и т.п.
В частности, я бы не стал слепо включать его в качестве замены для void*
, поскольку это может выделить память в куче, что может быть смертельно опасным для высокопроизводительного кода.
std::any
это словарный тип. Когда вам нужно сохранить что-нибудь, в качестве значения вы можете использовать его.
Существует несколько вариантов использования "первого уровня":
При взаимодействии с языками сценариев, которые сами имеют такие типы, это естественное соответствие.
Когда у вас есть дерево свойств с очень полиморфным содержимым, и структура дерева отделена от производителя и потребителя дерева.
При замене эквивалента
void*
кусок данных, передаваемых через промежуточный уровень, которому действительно все равно, что он несет.
Он также может быть использован в качестве строительного блока в других случаях. Например, std::function
может выбрать для хранения его значение в std::any
:
template<class R, class...Args>
struct func<R(Args...)> {
mutable std::any state;
R(*f)(std::any& state, Args&&...) = nullptr;
template<class T>
void bind(T&& t) {
state = std::forward<T>(t);
f = [](std::any& state, Args&&...args)->R {
return std::any_cast<T&>(state)(std::forward<Args>(args)...);
};
}
R operator()(Args...args)const {
return f(state, std::forward<Args>(args)...);
}
};
это довольно маленькая реализация (большая часть) std::function
, В основном я использовал any
набрать стереть копировать / переместить / уничтожить.
Вы можете использовать это в другом месте для подобных проблем (где вы стираете какую-то операцию, а также хотите набрать стирать, копировать / перемещать / уничтожать) или обобщать ее.
Он используется в Wt, чтобы обеспечить не шаблонный интерфейс для табличных данных.
Для встроенных и Wt-типов существуют преобразования в строку, и вы можете зарегистрировать дополнительные преобразования, Wt::any_traits
, Это позволяет отображать что-либо как запись в таблице, классы представления не должны ничего знать о типах, которые они отображают.