试图理解为什么这段代码不能用 gcc 和 clang 编译,但可以用 msvc 编译。
#include <type_traits>
class Incomplete;
template <class T>
struct Templated {
T t;
};
struct Test {
explicit Test(const Templated<Incomplete> &);
};
int main()
{
static_assert(std::is_move_constructible_v<Test>, "Not move constructible");
}
海湾合作委员会错误:
<source>: In instantiation of 'struct Templated<Incomplete>':
/opt/compiler-explorer/gcc-
13.2.0/include/c++/13.2.0/type_traits:3257:7: required from
'constexpr const bool std::is_move_constructible_v<Test>'
<source>:18:24: required from here
<source>:9:7: error: 'Templated<T>::t' has incomplete type
9 | T t;
| ^
<source>:5:7: note: forward declaration of 'class Incomplete'
5 | class Incomplete;
| ^~~~~~~~~~
Compiler returned: 1
Clang 错误在概念上是相同的。
如果删除
const
说明符或构造函数本身,代码将编译。尽管根本不应该使用构造函数,但为什么它会这样工作?
Templated<Incomplete>
可能有这样的构造函数:
Templated(Test&&);
如果是这样的话
Test unnamed(std::move(t));
,其中
t
是 Test
类型的变量,将是格式良好的。它将选择您的 Test
构造函数,并将 const Template<Incomplete>&
绑定到通过该构造函数构造的临时 Template<Incomplete>
对象。
那么
std::is_move_constructible_v<Test>
就是真的。
为了检查这种可能性,编译器必须实例化
Templated<Incomplete>
。
此实例化的格式不正确,因为
Templated<Incomplete>
具有在实例化时不完整的类型成员 (Incomplete
)。