我今天正在调试一个失败的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/

10-11 23:02
查看更多