std::optional::value_or() - 惰性参数评估

Posted

技术标签:

【中文标题】std::optional::value_or() - 惰性参数评估【英文标题】:std::optional::value_or() - lazy argument evaluation 【发布时间】:2019-01-12 16:47:47 【问题描述】:

是否可以以惰性方式评估 std::optional::value_or(expr) 参数,所以 expr 仅在没有值的情况下计算?

如果不是,什么是合适的替代品?

【问题讨论】:

【参考方案1】:

你可以编写你的辅助函数:

template<typename T, typename F>
T lazy_value_or(const std::optional<T> &opt, F fn) 
    if(opt) return opt.value();
    return fn();

然后可以用作:

T t = lazy_value_or(opt, []  return expensive_computation(););

如果这比显式输入要少得多,那由您来判断;不过,您可以使用宏使其更短:

#define LAZY_VALUE_OR(opt, expr) \
    lazy_value_or((opt), [&]  return (expr);)

用作

T t = LAZY_VALUE_OR(opt, expensive_calculation());

这与我认为你想要的最接近,但可能会因为它隐藏了太多东西而令人不悦。

【讨论】:

“你可以用一些宏来缓解这个问题”——请不要提倡使用宏。 @JesperJuhl 就像goto 一样,宏是一种工具,并且在现代 C++ 中也占有一席之地;在法庭上妖魔化他们,至于任何“绝对”的判断,都是错误的和短视的。这种情况有点边缘,因为它隐藏了很多东西(我什至警告过这一点),但这取决于 OP 来判断。 它们是工具箱中的工具,当然。他们有他们的用途。但是,我认为我们不应该到处提倡使用它们,因为大多数 使用宏是不好的或不恰当的——大多数 事情可以在不使用宏的情况下做得更好。所以是的,它们存在。他们有一个目的。除非它们是最后也是唯一的手段(恕我直言),否则不要提及它们。 作为命名说明,某些语言(例如 Rust)将其称为 value_or_else【参考方案2】:
#include <optional>

template <typename F>
struct Lazy

    F f;  

    operator decltype(f())() const
    
        return f();
    
;

template <typename F>
Lazy(F f) -> Lazy<F>;

int main()

    std::optional<int> o;

    int i = o.value_or(Lazy[]return 0;);

DEMO

【讨论】:

template &lt;typename F&gt; Lazy(F f) -&gt; Lazy&lt;F&gt;; 是什么样的构造?它看起来像一个带有尾随返回类型的函数模板的前向声明,但它不是...... @BenVoigt 这是一个模板演绎指南 operator decltype(auto)() const 是更好的 IMO(更少的括号)。 :) @Rakete1111 哦,天哪,这让我的大脑崩溃了......“嘿,这是一个转换......嗯......我们会看到的!” @Rakete1111 还有operator invoke_result_t&lt;F&gt;()【参考方案3】:

选择函数类型。

然后可以传入一个 lambda,调用它时会在请求的时刻计算正确的值。

std::optional<std::function<int()>> opt;

int a = 42;
opt = [=]  return a; 

int b = 4;

int c = opt.value_or([=]  return b * 10 + 2;) ();

【讨论】:

以上是关于std::optional::value_or() - 惰性参数评估的主要内容,如果未能解决你的问题,请参考以下文章