是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?
Posted
技术标签:
【中文标题】是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?【英文标题】:Is it possible to create std::any with std::reference_wrapper from just std::any? 【发布时间】:2020-01-08 18:50:07 【问题描述】:假设,我有一个 std::any
,其中存储类型 T。是否可以创建另一个包含std::reference_wrapper<const T>
类型的std::any
?喜欢
std::any original = std::string("Test string");
std::any reference;
// Magic here
auto ref = std::any_cast<std::reference_wrapper<const std::string>>(reference); // Works
【问题讨论】:
【参考方案1】:这是不可能的,除非您知道确切的存储类型(请参阅其他答案)或可能类型的列表(在这种情况下,您可以 switch
超过 original.type()
)。
【讨论】:
【参考方案2】:如果你非常想要这个,你可以围绕 std::any
创建一个小包装类,它在构造时捕获并类型擦除“转换为reference_wrapper
”操作:
class any_refable
public:
std::any ref() const return converter(any);
const std::any& get() const& return any;
const std::any&& get() const&& return std::move(any);
std::any& get() & return any;
std::any&& get() && return std::move(any);
any_refable() = default;
template <typename T, typename = std::enable_if_t<! std::is_same_v<std::decay_t<T>, any_refable>>>
any_refable(T&& v) : any(std::forward<T>(v)), converter(make_converter<std::decay_t<T>>())
template <typename T, typename = std::enable_if_t<! std::is_same_v<std::decay_t<T>, any_refable>>>
any_refable& operator=(T&& v) any = std::forward<T>(v); converter = make_converter<std::decay_t<T>>(); return *this;
private:
using converter_t = std::any (*)(const std::any&);
std::any any;
converter_t converter = nullptr;
template <typename T>
static converter_t make_converter()
return [](const std::any& any) return std::any(std::cref(std::any_cast<const T&>(any))); ;
;
DEMO
【讨论】:
看起来很有趣。从std::ANY
派生不会提供更直观的界面吗?
我在这里避免继承的原因有很多,这可能会填补另一个问题(这可能会因为过于基于意见而被关闭)。让我引用 Sutter 和 Alexandrescu 的书 C++ 编码标准 中的三个条目。第 34 条:“更喜欢组合而不是继承。继承是 C++ 中最紧密的耦合关系,仅次于友谊。”
第 35 项:“避免从不是设计为基类的类继承。使用独立类作为基类是严重的设计错误。避免从具体类继承。从具有公共非虚拟析构函数有未定义行为的风险。”第 37 项:“继承是可替代性。必须履行所有基础合同。” Here 是一个示例,说明继承如何使调用未定义的行为变得过于容易。诚然,作曲也可以做到这一点,但更难偶然做到。【参考方案3】:
以下作品:
#include <iostream>
#include <any>
#include <functional>
int main()
std::any original = std::string("Test string");
std::any ref = std::cref(std::any_cast<const std::string&>(original));
std::any_cast<std::string&>(original)[0] = 'X';
std::cout << std::any_cast<std::reference_wrapper<const std::string>>(ref).get() << '\n'; // Prints Xest string
编辑:正如评论中所说,这仅在编译时已知类型的情况下才有效。如果包含的对象的类型是任意的,这是不可能的,因为std::reference_wrapper
必须在某个时候构造,为此它需要知道它必须在编译时包装的类型,没有办法解决这个问题,因为C++ 是静态类型的。
【讨论】:
这需要你知道确切的存储类型,所以有点作弊。以上是关于是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以将两个任意函数与 C++17 中的 std::any 进行比较?
带有 std::any 和 std::optional 的 any_cast