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

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

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

【问题讨论】:

    标签: c++ stl c++17 stdoptional


    【解决方案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;}) ();
    

    【讨论】:

      猜你喜欢
      • 2014-02-08
      • 1970-01-01
      • 2013-03-11
      • 2017-01-18
      • 2018-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多