当切换到 c++17 并用标准解决方案替换自定义 std::optional
解决方案时,检测到 clang 5 的一个非常奇怪和意外的行为。出于某种原因,由于对参数类的 std::is_constructible
特征的错误评估,emplace()
被禁用。
在复制之前必须满足一些特定的先决条件:
#include <optional>
/// Precondition #1: T must be a nested struct
struct Foo
{
struct Victim
{
/// Precondition #2: T must have an aggregate-initializer
/// for one of its members
std::size_t value{0};
};
/// Precondition #3: std::optional<T> must be instantiated in this scope
std::optional<Victim> victim;
bool foo()
{
std::optional<Victim> foo;
// An error
foo.emplace();
/// Assertion is failed
static_assert(std::is_constructible<Victim>::value);
}
};
godbolt.org 上的实时示例
更改任何先决条件并按预期编译。标准中是否存在一些未知的不一致,导致 clang 在合规的同时拒绝此代码?
附带说明:GCC 7.1 和 GCC 7.2 对上述代码没有任何问题。
错误报告:bugs.llvm.org
最佳答案
这看起来像一个编译器错误。来自 [class]
A class is considered a completely-defined object type (or complete type) at the closing
}
of the class-specifier.
这意味着Victim
在 std::optional<Victim>
完成,使其与此上下文中的任何其他类型没有什么不同。
来自 [meta]
The predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet
:T t(declval<Args>()...);
直接初始化t
参数类型为 Args...
, 或者如果 sizeof...(Args) == 0
, 它是值初始化 t
.
在这种情况下,value-initializing t
is to default-initialize t
,因此有效 std::is_constructible_v<Victim>
应该是真的。
话虽如此,编译器似乎是 struggling a lot编译这个。
关于c++ - clang 5:std::optional 实例化参数类型的 std::is_constructible 特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47974898/