【问题标题】:How to in-place-construct an optional aggregate?如何就地构建可选聚合?
【发布时间】:2021-07-21 18:31:26
【问题描述】:

如何就地构造可选聚合?看来我只能构造一个可选的单一事物,而不是可选的事物聚合。

#include <optional>
#include <iostream>

struct Unmovable
{
    Unmovable(const Unmovable&) = delete;
    Unmovable(Unmovable&&) = delete;
    Unmovable& operator=(const Unmovable&) = delete;
    Unmovable& operator=(Unmovable&&) = delete;

    explicit Unmovable(const char* msg) {
        std::cout << msg << '\n';
    }
};

struct Things
{
    Unmovable one;
    Unmovable two;
};

int main(int argc, char* argv[]) {
    const bool y = argc > 1 && argv[1][0] == 'y';

    std::optional<Unmovable> optionalThing = y
        ? std::optional<Unmovable>{"works"}
        : std::nullopt;
    
    std::optional<Things> optionalThings = y
        ? std::optional<Things>{
#if ATTEMPT == 1
            "jadda", "neida"
#elif ATTEMPT == 2
            {"jadda", "neida"}
#elif ATTEMPT == 3
            Things{"jadda", "neida"}
#elif ATTEMPT == 4
            Unmovable{"jadda"}, Unmovable{"neida"}
#elif ATTEMPT == 5
            {Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 6
            Things{Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 7
            std::in_place_t{}, "jadda", "neida"
#elif ATTEMPT == 8
            std::in_place_t{}, {"jadda", "neida"}
#elif ATTEMPT == 9
            std::in_place_t{}, Things{"jadda", "neida"}
#elif ATTEMPT == 10
            std::in_place_t{}, Unmovable{"jadda"}, Unmovable{"neida"}
#elif ATTEMPT == 11
            std::in_place_t{}, {Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 12
            std::in_place_t{}, Things{Unmovable{"jadda"}, Unmovable{"neida"}}
#endif
        } : std::nullopt;
}

【问题讨论】:

  • 标准库类型通常使用()来初始化成员,因此不支持聚合初始化。这里特别是:eel.is/c++draft/optional#ctor-13
  • 因此,您可以通过为 Things 提供构造函数或使用转发到 {}-style init: compiler-explorer.com/z/P431GjaEv 的包装器类型来解决此问题。
  • 查看emplace()的文档。
  • Things(char const* msg1, char const* msg2) : one{msg1}, two{msg2} {}std::make_optional&lt;Things&gt;("jadda", "neida")
  • @SamVarshavchik emplace 无法工作,原因与 std::in_place_t 构造函数重载不起作用的原因相同。

标签: c++ c++17 aggregate-initialization construction stdoptional


【解决方案1】:

如果你能用C++20,那你想要的是

std::optional<Things>{std::in_place, "jadda", "neida"};

live example 所示。你需要 C++20 的原因是 std::in_place_t 构造函数使用了

T(std::forward<Args>(args)...)

初始化对象,但() 仅适用于具有构造函数的类,Things 没有。 C++ 已更新以解决此问题,并且该更改使其成为 C++20。

在 C++17 中,您可以通过为 Things 提供一个将初始化成员的构造函数来使此代码工作。看起来像

struct Things
{
    Things(const char* msg1, const char* msg2) : one(msg1), two(msg2) {}
    Unmovable one;
    Unmovable two;
};

int main()
{
    std::optional<Things>{std::in_place, "jadda", "neida"};
}

你可以看到在这个live example中工作


如果您好奇,可以在 [dcl.init.general]/15.6.2.2 中找到在 C++20 中添加的用于处理此问题的新语言

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    相关资源
    最近更新 更多