К моменту времени, когда создается экземпляр Base<Derived1>
(в самом начале определения Derived1
), класс Derived1
является неполным, поскольку он является тем, который до конца своего объявления. Действительно, невозможно иметь полный тип в CRTP, поскольку производный тип никогда не будет завершенным, пока вы не объявите его наследование.
Для нестатических c членов данных единственный способ обойти это - использовать какой-то указатель на неполный тип (наиболее вероятно, std::unique_ptr
). Для членов stati c это также работает, но может также просто разделить объявление и определение члена stati c. Поэтому вместо
template<Impl>
struct Base {
static Impl impl{};
};
напишите
template<Impl>
struct Base {
static Impl impl;
};
и определите его следующим образом
template<Impl>
static Base<Impl>::impl ={};
после завершения Derived1
. (Обратите внимание, что я не уверен, как это работает для частных пользователей c). На мой взгляд, было бы лучше, если бы каждая реализация делала это для себя сама, то есть после завершения Derived1
добавьте
template<>
static Base<Derived1>::impl = {};
, иначе, думаю, получить правильный порядок для нескольких реализаций будет непросто.