带有 std::any 和 std::optional 的 any_cast

Posted

技术标签:

【中文标题】带有 std::any 和 std::optional 的 any_cast【英文标题】:any_cast with std::any's and std::optional 【发布时间】:2016-10-06 14:48:50 【问题描述】:

如果我将T 放入std::any,我可以使用any_cast<T>(my_any) 得到它。但是标准(= C++17,目前处于投票阶段)是否包含像 any_cast<T>(optional<any> oa) 这样的函数,如果 oa 是 nullopt,则返回 nullopt,否则返回 std::any_cast<T>(oa.value())?或者类似的东西?

编辑:由于人们似乎在建议实现,我也将列出我现在使用的:

/* using magic here to select between boost/std::experimental/std versions */

template<typename T>
inline const optional<T> any_cast(const optional<any>& operand)

    return operand ? 
        optional<T>(any_cast<T>(operand.value())) :
        optional<T>(nullopt);

【问题讨论】:

【参考方案1】:

std::optional proposal 或std::any proposal 中没有提及类似的内容。

我认为使用延续函数来实现是微不足道的,因为返回类型根据可选对象的状态而有所不同:

template <typename T, typename TOptional, typename TF>
void any_cast_or_nullopt(TOptional&& o, TF&& f)

    if(!o) return; 
    f(std::any_cast<T>(*o));

在适当的地方添加static_assert 和/或SFINAE 以约束函数。值*o 也应该根据o 的值类别转发。示例用法:

int out = -1;

std::optional<std::any> x;
x = 10;

any_cast_or_nullopt<int>(x, [&out](int value)
    
        out = value;
    );

assert(out == 10);

【讨论】:

我喜欢你的建议,但你真的需要 3 个模板参数吗? 如果你想要正确性和灵活性,是的:T 用于any_castTOptional 用于完美转发可选值; TF 用于通用可调用对象。你可以在没有TOptional 的情况下实现它,但是当o 作为右值传递时,你需要重复代码才能正确移动*o 但我没有 f。你强迫我将演员阵容与其结果的使用结合起来 - 这不像任何演员。 @einpoklum:您要求一个函数,该函数给出optional&lt;any&gt; 和模板参数T 返回T 实例或nullopt - 这是不可能的,因为T 和@ 987654342@ 是不相关的类型,因为 optional 的状态仅在运行时才知道。您可以让函数返回 optional&lt;T&gt; (如 Barry 建议的那样),或使用延续函数以便按照我的建议直接使用 T 当然该函数应该返回一个可选的,这就是我返回 T 或 nullopt 的意思……但是好吧,我明白你为什么做了你所做的。你基本上实现了and_then【参考方案2】:

如果std::optional 有一个bind(或and_then)成员函数(即optional&lt;T&gt; 上的一个函数,它接受T -&gt; optional&lt;U&gt; 并调用它或返回nullopt),那么就是这样您正在寻找:

std::optional<std::any>> oa;

optional<T> opt_t = oa.bind([](std::any& v) -> std::optional<T> 
    if (T* t = std::any_cast<T>(&v)) 
        return *t;
    
    else 
        return std::nullopt;
    
);

或者,如果你真的想直接调用any_cast&lt;T&gt;并处理抛出,map

optional<T> opt_t = oa.map([](std::any& v) 
    return std::any_cast<T>(v);
);

std::optional 虽然没有延续函数,所以你必须把它们写成非成员函数。

【讨论】:

以上是关于带有 std::any 和 std::optional 的 any_cast的主要内容,如果未能解决你的问题,请参考以下文章

使用带有decltype的std :: any_cast…为什么这段代码会抛出错误的any_cast?

`boost::any` 和 `std::any` 之间的区别

为啥在 dlopen'd 函数中传递的 std::any 的 std::any_cast 会引发错误

std::any - 为啥它缺少这么多运算符?

是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?

我啥时候应该使用 std::any