Начиная с 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
это выгодно.
Когда использовать
void*
как крайне небезопасный шаблон с некоторыми ограниченными случаями использования, std::any
добавляет безопасность типов, и поэтому у него есть реальные варианты использования.
Некоторые возможности:
Я бы назвал это классическим «используйте, когда вы не можете избежать этого».
Я могу думать только о не критичных к производительности реализациях языков сценариев с динамической типизацией для представления переменных из мира сценариев, но даже с натяжкой (Boost.Spirit / пример / й / compiler_tutorial делает это без, как для парсера и времени выполнения).
Для всего остального от парсеров (например, Boost.Spirit.X3) к API библиотеки (например, ASIO) обычно существует более быстрая / лучшая / более конкретная альтернатива, поскольку очень немногие вещи действительно являются «чем-то», большинство из них более конкретны, чем это.
std::variant
и / или std::optional
для «почти любой стоимости»std::packaged_task
/ std::function
+ лямбда-выражения для «обратного вызова с аргументами», что было бы в случае void*
в C API.В частности, я бы не стал слепо включать его в качестве замены для void*
, как это может выделить памяти в куче, что может быть смертельно опасным для высокопроизводительного кода.
Он используется в Wt, чтобы обеспечить не шаблонный интерфейс для табличные данные.
Для встроенных и Wt-типов существуют преобразования в строку, и вы можете зарегистрировать дополнительные преобразования, Wt::any_traits
. Это позволяет отображать что-либо как запись в таблице, классы представления не должны ничего знать о типах, которые они отображают.
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
набрать стереть копировать / переместить / уничтожить.
Вы можете использовать это в другом месте для подобных проблем (где вы стираете какую-либо операцию, а также хотите набрать стирать, копировать / перемещать / уничтожать), или обобщить это.