我什么时候应该使用std :: any

sch*_*312 10 c++ c++17 stdany

自从std::any引入C++ 17以来.现在可以编写这样的代码了

#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;
}
Run Code Online (Sandbox Code Playgroud)

双被分配给变量var和比std::string被分配给它.

为什么要std::any介绍?

我认为这违反了least astonishment rule,因为我发现很难想到一种情况,这可以用来表达更清楚,我想表达的内容.

有人能给我一个很好的例子吗std::any

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

May*_*yur 10

什么时候使用
void*作为一个非常不安全的模式与一些有限的用例,std::any添加类型安全性,这就是为什么它有一些真实的用例.

一些可能性:

  • 在库中 - 当库类型必须在不知道可用类型集的情况下保存或传递任何内容时.
  • 解析文件 - 如果您确实无法指定支持的类​​型是什么.
  • 消息传递.
  • 使用脚本语言绑定.
  • 为脚本语言实现解释器
  • 用户界面 - 控件可能包含任何内容
  • 编辑中的实体
    (参考)

  • @Klaus:用例是当*某些*代码知道所存储的类型,但该代码不负责该数据的*生命周期*(可能包括制作副本)。 (5认同)
  • “*实现脚本语言的解释器*”就是一个很好的例子。特别是与“*与脚本语言的绑定*”相结合。我发现在实现受限 Python 解释器时使用“std::any”非常方便。 (3认同)
  • "如果你真的不能指定支持的类​​型是什么." 意味着将"任何东西"读入某种存储.好.以及如何使用该数据?如果我不知道std :: any中包含的内容,我不知道如何处理这些数据.如果我知道如何处理数据,我知道潜在存储类型的列表.这就是std :: variant.我无法理解......你能解释一下吗? (2认同)

Yak*_*ont 7

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)...);
  }
};
Run Code Online (Sandbox Code Playgroud)

这是(大部分)的一个相当小的实现std::function。基本上我习惯于any输入擦除复制/移动/销毁。

您可以在其他地方使用它来解决类似的问题(您正在键入擦除某些操作并且还想键入擦除复制/移动/销毁),或将其概括


bob*_*bah 5

我将其总结为经典的“在无法避免时使用”。

我只能想到动态类型脚本语言的非性能关键实现来表示来自脚本世界的变量,但即使如此(Boost.Spirit/example/qi/compiler_tutorial没有这样做,对于解析器和运行)。

对于从解析器(例如Boost.Spirit.X3)到库 API(例如ASIO)的其他所有内容,通常会有更快/更好/更具体的替代方案,因为很少有东西是真正的“任何东西”,大多数都比这更具体.

  • std::variant和/或std::optional“几乎任何价值”
  • std::packaged_task/ std::function+ 用于“带参数回调”的 lambda,这将是void*C API 中的一种情况。
  • 等等。

具体来说,我不会盲目地将它作为 a 的替代品void*,因为它可能会在堆上分配内存,这对于高性能代码来说可能是致命的。