【发布时间】:2020-08-27 20:52:06
【问题描述】:
考虑以下带有std::optional 的结构,其中包含肯定具有“正常”默认构造函数的类型。
#include <optional>
#include <string>
struct Foo
{
Foo() = default;
const std::optional<std::string> m_value;
};
bool function()
{
Foo foo;
return bool(foo.m_value);
}
使用 clang 9 编译以下代码(使用系统默认的 libstdc++,用于其 gcc 8)会给出意外警告:
<source>:6:5: warning: explicitly defaulted default constructor is implicitly deleted [-Wdefaulted-function-deleted]
Foo() = default;
^
<source>:7:38: note: default constructor of 'Foo' is implicitly deleted because field 'm_value' of const-qualified type 'const std::optional<std::string>' (aka 'const optional<basic_string<char> >') would not be initialized
const std::optional<std::string> m_value;
^
Foo foo; 也存在硬错误,因为它使用了已删除的构造函数。
- 删除
Foo() = default;构造函数会得到相同的结果。 - 将其替换为
Foo() {}有效! - 删除所有构造函数并将
foo初始化为Foo foo{};有效! - 将成员显式初始化为
const std::optional<std::string> m_value{};有效! - 从成员中删除
const有效! (但意思不一样) - 将 clang 9 与
-stdlib=libc++一起使用有效! - 使用 gcc 8.3(仍然使用
libstdc++)有效!
我读过std::optional - construct empty with {} or std::nullopt? 这似乎表明= default 构造函数std::optional 的libstdc++ 实现选择很可能是罪魁祸首。但是,在那个问题上,关注的是一种方法与另一种方法的效率问题。在这种情况下,这似乎是一个正确性的问题。
(我怀疑How can std::chrono::duration::duration() be constexpr? 的答案将成为这里故事的一部分。)
我在 Compiler Explorer 上看到了相同的行为:https://gcc.godbolt.org/z/Yj1o5P
比较可选和非可选std::string 的简单结构(在非工作配置中):
struct Foo { const std::optional<std::string> m_value; };
auto f1() { Foo f; return f.m_value; } // Fails: call to implicitly deleted constructor.
struct Bar { const std::string m_value; };
auto f2() { Bar b; return b.m_value; } // Works.
这是libstdc++ 中的错误吗? clang 和libstdc++ 之间的意图和假设是否混合?
当然,我的意图不可能是我可以有一个带有const std::string 的结构,但我不能有一个带有const std::optional<std::string> 的结构,除非我写了一个构造函数?
(在实际情况下,您也会有额外的构造函数。因此,= default() 构造函数的动机首先是。那,并且clang-tidy。)
编辑:这是示例的扩展版本 (Compiler Explorer),显示了在“纯 clang”、“纯 gcc”中工作的类似示例,但在混合“clang+libstdc++”中失败。这个稍微大一点的例子仍然是人为的,但暗示了为什么人们可能想要真正拥有这样一个默认构造函数。
struct Foo
{
Foo() = default; // Implicitly deleted?!
explicit Foo(std::string arg) : m_value{std::move(arg)} {}
const auto& get() const noexcept { return m_value; }
private:
const std::optional<std::string> m_value;
};
// Maybe return an empty or a full Foo.
auto function(bool flag, std::string x)
{
Foo foo1;
Foo foo2{x};
return flag ? foo1 : foo2;
}
【问题讨论】:
-
[dcl.init]/7可能是罪魁祸首。 -
const int成员 (godbolt) 存在编译错误,因此问题可能与= deafult和const成员变量有关。 -
std::optional绝对与它有关。是因为const。 -
@IlCapitano:
const int value;删除默认构造函数我并不感到惊讶(因为int缺少构造函数)。但似乎const optional<T> value;应该 工作,不管T是什么,尤其是当const T value;工作时。 -
@n.'pronouns'm。当
const string x有效但const optional<string> x无效时,您能帮我理解它与optional无关吗?以及为什么“纯clang+libc++”有效,“纯gcc+libstdc++”有效,而“混合clang+libstdc++”无效?
标签: c++ c++17 language-lawyer clang++ libstdc++