Страницы

Поиск по вопросам

понедельник, 10 июня 2019 г.

Возможен ли шаблон со строго определёнными типами?

Есть функция, которая использует один из двух классов потомков и вызывается через std::thread(MyFunc, std::ref(SpecifiedClassType)).detach() У класса-родителя нет некоторых методов потомков, поэтому объявлять объекты потомков типом родителя не вариант.
Можно ли как-то указать какие именно классы могут быть переменной в этой функции, или кроме template вариантов нет?
Пояснение:
Есть класс Capture у которого два потомка - Camera и Screen. Назначение этой системы - получение кадров с камеры или скриншотов экрана - и более ничего (сети там быть не должно). У родителя есть общая для потомков функция GrabJPG, которая вызывается во внешней функции, в потоке. Я хочу, чтобы та функция MyFunc, что я упомянул в начале темы, выглядела примерно так:
void StreamThread(STREAMER &cgf, <только_тип_Camera_или_Screen> &source){ // где cfg - структура с параметрами сетевой конфигурации, // а source - источник кадров - камера или экран. // ... cgf.connection->open(cgf.host, cgf.port) // ... туда-сюда настройки while (cgf.connection->active()){ // ... int size = source->GrabJPG(&buffer); if( size){ cgf.connection->transmit(buffer, size); } // ... } }
Сейчас у меня два таких абсолютно одинаковых StreamThread-а, различающихся только одной переменной - классом камеры или экрана. Не красиво, согласитесь? Должна быть ошибка компиляции, если попытаться засунуть в функцию любой другой класс, не являющийся потомком Capture. Вот, что требуется.


Ответ

Есть несколько подходов к решению подобной проблемы:
Явное инстанцирование
+ Определения для обоих вариантов StreamThread будут сгенерированы автоматически на основе общего шаблонного кода с помощью директив явного инстанцирования (в том файле, где эти директивы будут указаны).
+ (C++11 и выше) Неявное инстанцирование шаблона функции StreamThread для шаблонных аргументов Camera и Screen можно запретить во всех единицах трансляции, куда будет подключен заголовочный файл StreamThread.h
– При попытке скомпилировать функцию StreamThread со значением шаблонного аргумента, отличного от Camera или Screen, будет выдана ошибка линковки (а не компиляции).
// StreamThread.h
template void StreamThread(SREAMER &cgf, Source &source);
extern template void StreamThread(SREAMER &cgf, Camera &source); // C++11 и выше
extern template void StreamThread(SREAMER &cgf, Screen &source); // C++11 и выше
// StreamThread.cpp
template void StreamThread(SREAMER &cgf, Source &source) { // ... }
template void StreamThread(SREAMER &cgf, Camera &source);
template void StreamThread(SREAMER &cgf, Screen &source);
Ограничение множества типов, которые могут использоваться в качестве аргумента шаблона, с помощью SFINAE
При использовании данного подхода будут выдаваться ошибки компиляции в случае несовпадения аргумента шаблонной функции с Camera или Screen
// StreamThread.h
#include
template std::enable_if_t || std::is_same_v> StreamThread(SREAMER &cgf, Source &source) { // ... }
+ При попытке скомпилировать функцию StreamThread со значением шаблонного аргумента, отличного от Camera или Screen, будет выдана ошибка компиляции (о том, что нужная перегрузка функции StreamThread не найдена).
– Шаблон функции StreamThread будет неявно инстанцирован во всех единицах трансляции, куда подключен заголовочный файл StreamThread.h и где происходит вызов функции StreamThread
Комбинированный подход
Объединяет два предыдущих варианта и совмещает в себе их плюсы.
// StreamThread.h
#include
template std::enable_if_t || std::is_same_v> StreamThread(SREAMER &cgf, Source &source);
extern template void StreamThread(SREAMER &cgf, Camera &source); // C++11 и выше
extern template void StreamThread(SREAMER &cgf, Screen &source); // C++11 и выше
// StreamThread.cpp
template std::enable_if_t || std::is_same_v> StreamThread(SREAMER &cgf, Source &source) { // ... }
template void StreamThread(SREAMER &cgf, Camera &source);
template void StreamThread(SREAMER &cgf, Screen &source);

Комментариев нет:

Отправить комментарий