我应该什么时候使用 std::any
When should I use 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
是有益的。
何时使用
void*
作为一种极其不安全的模式,具有一些有限的用例,std::any
增加了类型安全,这就是它有一些实际用例的原因。
一些可能性:
- 在库中 - 当库类型必须在不知道
一组可用类型。
- 解析文件 - 如果您真的无法指定支持的文件
类型。
- 消息传递。
- 与脚本语言的绑定。
- 为脚本语言实现解释器
- 用户界面 - 控件可能包含任何内容
- 编辑器中的实体
(ref)
我会总结为经典"use when you cannot avoid it"。
我只能想到动态类型脚本语言的非性能关键实现来表示来自脚本世界的变量,但即使是这样(Boost.Spirit/example/qi/compiler_tutorial 没有,对于解析器和运行时)。
对于来自解析器的所有其他内容(例如 Boost.Spirit.X3) to library APIs (e.g. ASIO)通常会有一个 faster/better/more-specific 替代方案,因为很少有东西是真正的 "anything",大多数比那更具体。
std::variant
and/or std::optional
对于 "almost any value"
std::packaged_task
/ std::function
+ "callback with arguments" 的 lambda,在 C API 中就是 void*
的情况。
- 等等
具体来说,我不会盲目地将它作为 void*
的替代品,因为它 内存在堆上,这对于高性能代码来说可能是致命的。
在Wt中使用,为tabular data提供非模板接口。
内置类型和 Wt 类型可以转换为字符串,您可以通过特化 Wt::any_traits
来注册其他转换。这允许任何内容显示为 table 中的条目,视图 类 不必知道它们显示的类型。
std::any
是 词汇 类型。当您需要存储任何东西时,您可以使用它作为值。
它有多种 "first level" 用途:
与本身具有此类类型的脚本语言进行交互时,这是一种自然的契合。
当你有一个属性树,内容高度多态,并且树的结构与树的生产者和消费者解耦。
当替换相当于 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
来输入擦除 copy/move/destroy.
您可以在其他地方使用它来解决类似的问题(您正在键入擦除某些操作并且还想键入擦除 copy/move/destroy),或者 .
自引入 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
增加了类型安全,这就是它有一些实际用例的原因。
一些可能性:
- 在库中 - 当库类型必须在不知道
一组可用类型。
- 解析文件 - 如果您真的无法指定支持的文件
类型。
- 消息传递。
- 与脚本语言的绑定。
- 为脚本语言实现解释器
- 用户界面 - 控件可能包含任何内容
- 编辑器中的实体
(ref)
我会总结为经典"use when you cannot avoid it"。
我只能想到动态类型脚本语言的非性能关键实现来表示来自脚本世界的变量,但即使是这样(Boost.Spirit/example/qi/compiler_tutorial 没有,对于解析器和运行时)。
对于来自解析器的所有其他内容(例如 Boost.Spirit.X3) to library APIs (e.g. ASIO)通常会有一个 faster/better/more-specific 替代方案,因为很少有东西是真正的 "anything",大多数比那更具体。
std::variant
and/orstd::optional
对于 "almost any value"std::packaged_task
/std::function
+ "callback with arguments" 的 lambda,在 C API 中就是void*
的情况。- 等等
具体来说,我不会盲目地将它作为 void*
的替代品,因为它
在Wt中使用,为tabular data提供非模板接口。
内置类型和 Wt 类型可以转换为字符串,您可以通过特化 Wt::any_traits
来注册其他转换。这允许任何内容显示为 table 中的条目,视图 类 不必知道它们显示的类型。
std::any
是 词汇 类型。当您需要存储任何东西时,您可以使用它作为值。
它有多种 "first level" 用途:
与本身具有此类类型的脚本语言进行交互时,这是一种自然的契合。
当你有一个属性树,内容高度多态,并且树的结构与树的生产者和消费者解耦。
当替换相当于
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
来输入擦除 copy/move/destroy.
您可以在其他地方使用它来解决类似的问题(您正在键入擦除某些操作并且还想键入擦除 copy/move/destroy),或者