Gre*_*ape 16 c++ language-lawyer c++17 stdoptional
当切换到c ++ 17并用std::optional标准解决方案替换自定义解决方案时,检测到clang 5的一个非常奇怪和意外的行为.出于某种原因,emplace()由于对std::is_constructible参数类的特征的错误评估而被禁用.
在复制之前必须满足一些特定的前提条件:
#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);
}
};
Run Code Online (Sandbox Code Playgroud)
更改任何前提条件并按预期编译.标准中是否存在一些未知的不一致性,使得clang在符合要求时拒绝此代码?
作为旁注:GCC 7.1和GCC 7.2对上述代码没有任何问题.
错误报告:bugs.llvm.org
这看起来像编译器错误.来自[班级]
}在类说明符结束时,类被视为完全定义的对象类型(或完整类型).
这意味着Victim完成std::optional<Victim>,使其与此上下文中的任何其他类型没有区别.
来自[meta]
is_constructible<T, Args...>当且仅当以下变量定义适用于某些发明变量时,才应满足模板特化的谓词条件t:T t(declval<Args>()...);
哪个是t使用类型的参数进行直接初始化Args...,或者是否sizeof...(Args) == 0是值初始化t.
在这种情况下,value-initializing t是default-initialize t,这是有效的,因此std::is_constructible_v<Victim>应该为true.
说了这么多,编译器似乎是挣扎了很多编写本.