Создание вариационного шаблона класса с набором перегрузок функций на основе временных аргументов? - PullRequest
2 голосов
/ 03 апреля 2019

Мотивация : мне нужно создать базовый класс для библиотеки 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 * с его идентификатором и переведите его обратно в тот момент, чтобы выполнить соответствующий перегруженный вызов. , Недостаток: этот метод будет непростым для обеспечения безопасности типов и минимизации объема работы, которую должен выполнить конечный пользователь.

Прямо сейчас я склоняюсь к реализации первой из этих альтернатив и провожу некоторое тестирование производительности, чтобы сравнить ее с моей рабочей версией, но мне бы очень хотелось, если есть что-то более чистое, что мне не хватает.

1 Ответ

4 голосов
/ 03 апреля 2019

Ваша реализация подходит для C ++ 14.

C ++ 17 допускает переменную using, чтобы избежать рекурсии:

template <typename T>
struct MyClassImpl
{
    virtual ~MyClassImpl() = default;
    virtual bool MyFunction(T in) = 0; // or { return true; }
};

template <typename... Ts>
struct MyClass : public MyClassImpl<Ts>...
{
    using MyClassImpl<Ts>::MyFunction...;
};

Демо

...