c++ - 不稳定类型特征背后的原因是什么?

标签 c++ types llvm standards

我今天正在调试一个失败的 clang 构建。该构建基本上失败了,因为 is_default_constructible 评估为 false。在将问题一分为二几个小时后,我将问题减少到最小的情况:

#include <type_traits>
#include <string>

namespace A {
    // This has been extracted from an old (outdated(?))
    // implementation of an optional type

    struct empty_t {};

    template<class T>
    struct o
    {
    public:
        template<class... U,
                 typename std::enable_if<
                     std::is_constructible<T, U...>::value,
                     bool
                     >::type = false
                 >
        o(empty_t, U&&... u) { }
    };

}

struct B
{
    struct Foo
    {
        //Foo () {};   // uncomment this line and it works
        bool x = true; // comment this line and it works
    };

    std::string c; // comment this line and it works, also change to int
    A::o<Foo> r;   // comment this line and it works

    static const bool b;
};

static_assert(
    std::is_default_constructible<B::Foo>::value,
    "not constructible!");

上面的例子在 g++ 6.3 和 7.0 下编译得很好。它在 clang++ 4.0.0 和 3.9.1 中失败——静态断言仅在那个非常具体的构造中失败,但它仍然破坏了我们的构建。正如您可以自己尝试的那样,一些最小的更改可以解决问题(例如评论其中提到的行)。结果看起来有些武断。

我想知道的是,clang 中明显的错误实际上是错误还是某种未定义的行为。实际上,这部分语言的定义有多明确?

如果有任何关于如何调试此类问题的建议,我也将不胜感激:是否有一种好方法可以从 clang 中获取一些信息,说明为什么它认为 Foo 不是默认可构造的?

最后,如果你们中的任何人都可以访问(符合标准的)第三个 C++ 实现并可以报告结果,那就太好了。

最佳答案

嵌套类的默认数据成员初始值设定项在外部类完成之前(即在外部类定义的分号处)不会被实例化。当使用类型特征在嵌套类完成时(即在其定义之后)但在外部类完成之前查询时,这会导致奇怪的结果。

您可以通过将 Foo 移到 B 之外来解决这个问题。

关于c++ - 不稳定类型特征背后的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44846377/

相关文章:

objective-c - 在 Objective-C ARC 中,什么是 "BPTRs declared within extern "BCPL“ block ”?

c++ - 运行时错误-f1.exe 不存在或不是可执行文件

c++ - 在 lambda 表达式中指定捕获的变量的目的是什么?

javascript - 当我们更改类型值时触发替换

c - LLVM API 指针类型支持

ios - 如何避免 3rd 方框架之间的重复符号

c++ - 关于 C++ 仿函数/lambda 参数传递在 STL 算法中的混淆

c++ - OpenGL 帧率不一致

haskell - 是否可以使 Traversal 成为 IsString 的实例

javascript - $FlowExpectedError 有什么作用?