Итак, у меня есть класс base
, не содержащий шаблонов, который содержит настройки по умолчанию для его методов.Затем я пытаюсь использовать наследование с шаблонным классом.Вот фрагмент примера кода для иллюстрации.
// enums for as a template selector
enum class version
{
ver1,
ver2,
ver3
};
// Base class with fabricated methods
struct base
{
virtual void propertyOne()
{
// some default action
}
virtual void propertyTwo()
{
// some default action
}
};
// derived class
template <version V>
struct derived : public base
{
virtual void propertyOne()
{
helper< One, V >();
}
virtual void propertyTwo()
{
helper< Two, V >();
}
}
Я использую вспомогательную функцию для выполнения «универсального» алгоритма для различных «полей», которые используются в признаках класса.
Например: поле является чем-то похожим на это
struct field
{
int thingone;
constexpr field(int i):thingone(i){}
};
В c ++ 11, чтобы дать внешним полям экземпляры полей, я обернул их как статические члены другой структуры (c ++ 14 ослабляет эти правила,Ну что ж).Вся причина, по которой я это делаю, заключается в том, что мне нужны значения константных выражений (например, переменная-член thingone необходима в качестве параметров шаблона другого метода, который требует, чтобы она была константным выражением).
struct fields
{
static constexpr field One{1};
static constexpr field Two{2};
};
// defining trait class from structure above
template< const field& T, revision R >
class fieldTraits;
// sample fieldTrait definitions for illustrative purposes
template< >
class fieldTraits< fields::One, revision::ver3>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "helper" algorithm
static constexpr size_t field_val = 1;
};
template< >
class fieldTraits< fields::Two, revision::ver1>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "helper" algorithm
static constexpr size_t field_val = 1;
};
// Main guts of the class methods above
template< const field& F, revision R, typename TT = traitClass<F,R> >
void helper()
{
// Let's pretend I'm doing something useful with that data
std::cout << F.thingone << std::endl;
std::cout << TT::field_val << std::endl;
}
Проблема, с которой я столкнулся, заключается в попытке создать экземпляр, например,
derived<revision::rev1> l_derived;
Поскольку я определил класс черт только для ver3
, я не могу создать экземпляр класса без определения класса черт для ver1
и ver2
явно.Но если классы признаков одинаковы, скажем, для ver1
- ver 3
, есть ли какое-либо условие enable_if, которое я должен был сделать этим классом шаблона действительным для всех revs <= ver3
?
Я не смог найти ничего в заголовке traits_type, который в основном предлагает проверки типа "время компиляции", такие как std::is_same
и т. Д.
Я знаю, один вариант - скопировать и вставить чертуклассы для ver1
- ver3
, но это казалось излишним, поскольку я хотел избежать копирования повторяющегося кода.
Другой вариант - создать разные классы для каждой ревизии и использовать динамический полиморфизм, где я могу определитькласс для каждой ревизии.И тогда мне нужно только включить изменения ревизий черт, где они необходимы.Например,
class derived_ver1 : public base
{
virtual void propertyOne()
{
helper< fields::One, revision::ver1 >();
}
virtual void propertyTwo()
{
helper< fields::Two, revision::ver1 >();
}
};
class derived_ver2 : public derived:ver1
{
virtual void propertyTwo()
{
helper< fields::Two, revision::ver2 >();
}
};
class derived_ver3 : public derived:ver2
{
virtual void propertyTwo()
{
helper< Two, revision::ver3 >();
}
};
В этом примере propertyOne()
может повторно использовать класс признаков из ревизии 1 для ревизии 2 и 3, поскольку он не изменился после предыдущей ревизии 1 (и позволяет избежать копирования и вставки черт).
Есть ли лучший дизайн, к которому я мог бы подойти?
В итоге: есть ли способ использовать мое исходное наследование шаблонов и использовать некоторую особенность шаблона (например, std::enable_if
), чтобы повторно использовать класс признаков для неопределенных ревизий.Вместо того, чтобы явно определять черту для каждой ревизии (которая приводит к копированию-вставке).
Или второй подход, использующий динамический полиморфизм, является лучшим способом сделать это (который я читал, увеличил стоимость поиска в vtable, чтоприходит с этим)?