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

时间:2017-06-30 12:19:56

标签: 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 ++实现并且可以报告结果,那将非常好。

1 个答案:

答案 0 :(得分:0)

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

你可以通过在B外移动Foo来解决这个问题。