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