【问题标题】:Idiomatic way to initialise std::optional from another std::optional and something else从另一个 std::optional 和其他东西初始化 std::optional 的惯用方法
【发布时间】:2018-04-07 06:06:40
【问题描述】:

我想从另一个std::optional 初始化一个std::optional 和一些附加参数,前提是后者std::optional 不为空。不幸的是std::optional::optional 4) 和 5) 不适合,因为参数的数量不同。

我能够想出以下内容,但仍然感觉过度。我特别不喜欢明确指定 lambda 的返回类型。

是否有更好的(如更简洁和更具表现力的)方式来实现这一点?

#include <iostream>
#include <optional>
#include <tuple>

struct A {
    A(std::optional<int> oi, float f, char c)
    :
        val{
            [&] () -> decltype(val) /* I don't like specifying type here */ {
                if (oi)
                    return {{*oi, f, c}};
                else
                    return std::nullopt;            
            }()
        }
    {
    }

    std::optional<std::tuple<int, float, char>> val;
};

int main()
{
    auto print = [](auto& r) {
        if (r)
            std::cout
                << std::get<0>(*r) << "; "
                << std::get<1>(*r) << "; "
                << std::get<2>(*r) << std::endl;
        else
            std::cout << "nullopt" << std::endl;
    };

    auto one = A({}, 1.0, 'c');
    print(one.val);

    auto two = A(10, 2.0, 'c');
    print(two.val);
}

Live example.

【问题讨论】:

  • val{ oi ? decltype(val){{*oi, f, c}} : std::nullopt }?
  • @zneak 是的,它会起作用,但我们可以摆脱decltype吗?
  • Typedef 呢?我认为你的双手被类型推断在这里的工作方式束缚了。
  • 处理这个问题的“真正惯用”方法是让flat_map 函数与std::optional 一起使用,但我认为没有标准函数。
  • std::tuple{*oi, f, c} 可能比decltype 更清晰,尽管它们并不完全相同。

标签: c++ optional c++17 idioms


【解决方案1】:

相信编译器会做正确的事:

A(std::optional<int> oi, float f, char c) {
    if (oi) {
        val.emplace(*oi, f, c);
    }
}

这当然也是map() 成员函数 的一个很好的用例,您可以将其编写为非成员函数:

A(std::optional<int> oi, float f, char c)
    : val(map(oi, [&](int i){ return std::tuple(i, f, c); }))
{ }

最近由 TartanLlama 在P0798 中提出。

【讨论】:

  • 那么在map() 在标准中之前的第一个示例中没有机会避免val 的默认构造?
  • @DevNull 这很糟糕吗?默认构造一个可选项只是设置一个布尔值。编译器会正确优化,我的例子和你的例子生成identical code
  • 不,这不是“坏”,我只是希望有一些方法可以将其保留在成员初始化程序列表中并避免显式指定类型。
  • @DevNull 上面的map 解决方案正是这样做的? (它是来自 Haskell 的 map 函数,有时称为 fmap
  • @Yakk 是的,但它不在标准中(可能还没有)。
猜你喜欢
  • 1970-01-01
  • 2021-02-06
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-10
相关资源
最近更新 更多