Ограниченный преждевременный отказ CRTP
Я пытаюсь реализовать производный класс, наследуемый от базового шаблона, с производным классом в качестве параметра шаблона (надеюсь, приведенный ниже пример проясняет ситуацию):
template <class T>
struct S
{
T f() {return T();}
};
struct D : public S<D>
{
};
Это также хорошо компилируется и работает с gcc,clang и msvc. Теперь я хочу «убедиться», что параметр шаблона наследуется от базового класса:
#include <concepts>
template <class T>
concept C
= requires ( T t )
{
{ t.f() };
};
template <C T>
struct S
{
T f() {return T();}
};
struct D : public S<D>
{
};
Однако это отвергается каждым компилятором, а clang дает наибольшую информацию:
error: constraints not satisfied for class template 'S' [with T = D]
struct D : public S<D>
^~~~
note: because 'D' does not satisfy 'C'
template <C T>
^
note: because 't.f()' would be invalid: member access into incomplete type 'D'
{ t.f() };
Я понимаю, откуда берется компилятор:
D
еще не полностью определено, когда ограничение должно быть проверено, поэтому оно терпит неудачу вместо необходимой информации. Тем не менее, я несколько разочарован тем, что не было предпринято никаких попыток завершить определение производного класса перед оценкой еще не поддающегося проверке ограничения.
Это поведение предназначено? Есть ли другой способ проверить наследование, которое действительно работает?
Кстати, в этом случае gcc выдает довольно бесполезное сообщение об ошибке .
1 ответ
Вы можете проверить требование в конструкторе по умолчанию базового класса
#include <type_traits>
template<class Derived>
class Base
{
public:
Base()
{
static_assert(std::is_base_of_v<Base<Derived>, Derived>);
}
};
class Derived : public Base<Derived>
{ };
Это также должно быть проверено в любых других определяемых пользователем не копируемых и не перемещаемых конструкторах базы. Это действительно как