Когда я должен использовать 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 это выгодно.

https://gcc.godbolt.org/z/-kepOD

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 это словарный тип. Когда вам нужно сохранить что-нибудь, в качестве значения вы можете использовать его.

Существует несколько вариантов использования "первого уровня":

  1. При взаимодействии с языками сценариев, которые сами имеют такие типы, это естественное соответствие.

  2. Когда у вас есть дерево свойств с очень полиморфным содержимым, и структура дерева отделена от производителя и потребителя дерева.

  3. При замене эквивалента 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, Это позволяет отображать что-либо как запись в таблице, классы представления не должны ничего знать о типах, которые они отображают.

Другие вопросы по тегам