Статический класс CRTP, не зная производного типа?

Учитывая следующее, рабочий код.

#include <iostream>

template<class Detail>
class AbstractLogger
{
public:
static void log(const char* str) {
Detail::log_detailled(str);
}
};

class Logger : public AbstractLogger<Logger>
{
public:
static void log_detailled(const char* str) {
std::cerr << str << std::endl;
}
};

int main(void)
{
AbstractLogger<Logger>::log("main function running!");
return 0;
}

Теперь я хочу поставить AbstractLogger в библиотеку, и пусть пользователь библиотеки определяет свой собственный регистратор, как Logger класс здесь. Это имеет один недостаток: AbstractLogger<Logger> нельзя использовать внутри библиотеки, так как библиотека не может знать Logger,

Заметки:

  • Пожалуйста, никаких виртуальных функций или вопросов, почему бы и нет. Кроме того, я знаю о подобной проблеме, что «статические виртуальные» члены недействительны. Может быть, есть обходной путь в CRTP 🙂
  • C ++ 11 будет интересен, однако мне нужен «обычный» C ++.

1

Решение

Обычный подход состоит в том, чтобы кодировать концепцию, обеспечивая при этом помощников, чтобы пользователи могли легко создавать типы, которые удовлетворяют одному или нескольким из этих концепций. Как пример, что-то вроде boost::iterator_facade является помощником CRTP, который облегчает пользователю написание итератора. Затем этот итератор может использоваться везде, где принят итератор — например, в конструкторе диапазона std::vector, Обратите внимание, что этот конкретный конструктор не знает заранее определенного пользователем типа.

В твоем случае, AbstractLogger будет помощником CRTP. Недостающий кусок будет определять, например, концепция логгера. В результате обратите внимание, что все, что требует регистратора, либо должно быть реализовано в виде шаблона, либо вам нужен контейнер для стирания типов для хранения произвольных регистраторов.

Проверка концепции (например, предоставленные Увеличение) удобны для этого вида программирования, поскольку они позволяют представлять концепцию с помощью реального кода.

1

Другие решения

Если вы имеете в виду, что вы хотите иметь библиотеку, которая использует это как механизм ведения журнала, не зная точного типа создания экземпляра, я бы посоветовал против этого.

Единственный способ сделать это при выполнении других ваших требований (то есть без виртуальных функций) состоит в том, что все ваши функции / типы в библиотеке, которые должны регистрироваться, преобразуются в шаблоны, которые принимают Logger тип. Конечным результатом является то, что большая часть вашего интерфейса становится шаблоном (хотя вы, вероятно, сможете переместить большую часть реализации в не шаблонный код, это сделает вашу жизнь намного сложнее, чем необходимо, и все равно будет генерировать намного больший двоичный код) ,

Если вы заботитесь о виртуальных функциях, это о производительности, то вам следует пересмотреть свой подход и проблемы, которые он вызывает. В частности, ведение журнала является дорого. Большинство библиотек журналов решают эту проблему, оптимизируя случай отсутствия регистрации (с помощью макросов, которые избегают вызова регистратора, если уровень журнала / группа / … не включены), но все еще оставляют динамическую диспетчеризацию для фактической записи. Стоимость динамической отправки незначительна по сравнению со стоимостью записи в консоль или файл, или даже со стоимостью генерации сообщения, которое будет записано в журнал (я предполагаю, что вы записываете не только литеральные строки)

2

Шаблонные классы не могут быть «помещены в библиотеку», так как они создаются экземпляром компилятором как специализация их параметров шаблона.

Вы можете поместить независимые от параметров вещи, используемые в реализации шаблона, в библиотеку.

0
По вопросам рекламы [email protected]