Мотивация : мне нужно создать базовый класс для библиотеки C ++ 17, который будет иметь перегрузки для виртуальной функции на основе типов, которые пользователь определяет во время компиляции. По сути, когда в базовом классе вызывается определенная перегрузка функции, я хочу убедиться, что в производном классе вызывается правильная версия. Мой первоначальный инстинкт состоял в том, чтобы создать функцию виртуального шаблона, но, конечно, C ++ не может этого допустить, потому что компилятор не будет знать, какие его версии поместить в таблицу виртуальных функций. Однако, поскольку я буду знать все типы во время компиляции, можно ли сделать сам базовый класс вариационным шаблоном и использовать аргументы шаблона для создания набора перегруженной версии виртуальной функции, которая потребуется?
Выражения сгиба являются правильными, потому что их нельзя использовать для объявления функций. Рекурсивные шаблоны кажутся многообещающими, но я беспокоюсь, что наличие длинной цепочки наследования для базового класса приведет к снижению производительности. Вот рабочий код, который у меня есть:
template <typename... Ts> class MyClass;
template <typename T, typename... Ts>
struct MyClass<T, Ts...> : public MyClass<Ts...> {
using MyClass<Ts...>::MyFunction;
virtual bool MyFunction(T in) { return true; }
};
template <>
struct MyClass<> {
virtual bool MyFunction(...) { return false; }
};
Должна ли эта техника быть достаточной? Или у кого-то есть другие идеи о том, как мне достичь этой цели?
Мои другие идеи включают в себя:
Ограничить количество аргументов шаблона, которые могут быть обработаны, и разрешить каждую перегрузку в зависимости от того, достаточно ли длинный список аргументов для его включения. Недостаток: этот метод будет произвольным ограничением на количество типов.
Используйте вариационный макрос для построения класса. Недостаток: эта техника была бы запутанной и не элегантной.
Создайте функцию для назначения типа идентификационному номеру в базовом классе, передайте его производному классу как void *
с его идентификатором и переведите его обратно в тот момент, чтобы выполнить соответствующий перегруженный вызов. , Недостаток: этот метод будет непростым для обеспечения безопасности типов и минимизации объема работы, которую должен выполнить конечный пользователь.
Прямо сейчас я склоняюсь к реализации первой из этих альтернатив и провожу некоторое тестирование производительности, чтобы сравнить ее с моей рабочей версией, но мне бы очень хотелось, если есть что-то более чистое, что мне не хватает.