Сценарий
Рассмотрим класс Logger
, который имеет функцию-член write()
, перегруженную для стандартных типов C ++, а также имеет несколько удобных шаблонов функций, таких как writeLine()
, которые внутренне вызывают write()
:
class Logger {
public:
void write(int x) { ... }
void write(double x) { ... }
...
template <typename T>
void writeLine(T x) { write(x); ... }
...
};
Рассмотрим далее подкласс FooLogger
, который добавляет дополнительные write()
перегрузки для типов, специфичных для домена (назовем два из них FooType1
и FooType2
):
class FooLogger : public Logger {
public:
using Logger::write;
void write(FooType1 x) { ... }
void write(FooType2 x) { ... }
...
};
( автономный пример программы на Ideone )
Проблема
FooLogger::write()
при прямом вызове теперь поддерживает любой аргумент, для которого либо из двух классов обеспечивает перегрузку.
Однако FooLogger::writeLine()
поддерживает только те типы аргументов, для которых класс Logger
имеет перегрузку write()
... он не видит дополнительных перегрузок write()
, объявленных в классе FooLogger
.
Я хочу , чтобы он их видел, так что его можно вызывать и с этими типами аргументов!
Текущее решение
Я заставил его работать, используя шаблон CURLYURURRING Template (CRTP):
template <typename TDerivedClass>
class AbstractLogger {
...
template <typename T>
void writeLine(T x) { static_cast<TDerivedClass*>(this)->write(x); ... }
};
class Logger : AbstractLogger {}
class FooLogger : public AbstractLogger<FooLogger> {
...
};
( автономный пример программы на Ideone )
Хотя он и выполняет свою работу, он достигается за счет увеличения сложности и скорости кода:
- Это сделало реализацию базового класса значительно труднее для чтения (см. Ссылку на Ideone) и сложнее поддерживать (не забывайте танцевать
static_cast
везде, где это необходимо, при добавлении большего количества кода в класс в будущем !)
- Требуется разделить
AbstractLogger
и Logger
на два класса.
- Поскольку базовый класс теперь является шаблоном класса, реализации всех его функций-членов должны теперь быть включены в заголовок (а не в файл
.cpp
) - даже те, которые не должны выполнять static_cast
вещь.
Вопрос
Учитывая вышесказанное, я ищу информацию от людей с опытом работы с C ++:
- Является ли CRTP подходящим инструментом для этой работы?
- Есть ли другой способ решить эту проблему?