c++ - clang 5:std::optional 实例化参数类型的 std::is_constructible 特征

标签 c++ language-lawyer c++17 stdoptional

当切换到 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.1GCC 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.

这意味着Victimstd::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 variable t: 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/

相关文章:

C++ 缓冲文件读取

c++ - 为什么C++在对Foo <T>::Foo(T &&)的调用中不能推断T?

c++ - 指向纹理数据的指针 - 垂直翻转数据

c++ - SFINAE/enable_if 基于字符串参数的内容?

c++ - 如何在 C++ 中使用 ffmpeg 流式传输 opencv Mat

c++ - 使用 CDatabase,我可以在不使用 CRecordSet 的情况下发送 SQL 吗?

c++ - 在 OpenGL 应用程序中动态更改着色器

c++ - 为什么模板模板参数不允许在参数列表后出现 'typename'

c++ - 在不同限定的结构成员上使用 reinterpret_cast 是否安全?

c++ - 是什么导致 move 赋值运算符不被调用?