问题
template <class T>
class Base {
static_assert(!std::is_default_constructible<T>::value,
"T must not be default constructible");
};
struct X1 : Base<X1> {};
struct X2 : Base<X2> {
X2() = default;
};
struct X3 : Base<X3> {
X3() {};
};
struct X4 : Base<X4> {
X4() : Base{} {};
};
struct Y1 {};
int main() {
// all compile. They shouldn't
X1 x1; X2 x2; X3 x3; X4 x4;
// all compile. They shouldn't:
Base<X1> bx1; Base<X2> bx2; Base<X3> bx3; Base<X4> bx4;
Base<Y1> by1; // static assert fires. This is the expected behavior
}
The static_assert
at class level doesn't fire for any of the X
classes. But kicks in for Y
(which doesn't derive Base
)
It works correctly if the static_assert
is moved inside the constructor of Base
What is the reason that is_default_constructible<T>
is always false at class level if T
derives from Base
?
Ideone
回答1:
When Base<X1>
is instantiated in the inheritance list of X1
, X1
is an incomplete type. This means that X1
is not default-constructible when the class-scope static_assert
is checked.
The constructor for Base
is only instantiated upon use, at which point X1
is now a complete type and is default-constructible. This is why the static_assert
fires when inside the constructor, but not at class-scope.
回答2:
As per TartanLlama's answer, T
is incomplete at class level when T
is X
.
I want to add this results in Undefined Behavior as T
must be a complete type for is_default_constructible
:
cppreference docs for is_default_constructible:
T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound. Otherwise, the behavior is undefined.
来源:https://stackoverflow.com/questions/34924432/crtp-stdis-default-constructible-not-working-as-expected