Передача шаблона в функцию без указания конкретного типа - PullRequest
1 голос
/ 04 ноября 2019

Можно ли передать шаблон в функцию без указания конкретного типа?

У меня есть базовый класс, который является шаблоном, и две его специализации. Вот пример базового класса:

template<typename T1, typename T2> class Dataset 
{
protected:
   std::vector<std::pair<T1, T2> > _data_buffer;
public:
   virtual void doSomething(MatrixRm& data) = 0;
}

Вот первый класс, который расширяет базовый класс:

class InMemoryDataset : public Dataset<MatrixRm, MatrixRm>
{
public:
    void doSomething(MatrixRm& data) override
    {
     ...
    }
}

А вот второй класс, который расширяет базовый класс:

class OnlineDataset : public Dataset<std::string, std::string>
{
public:
    void doSomething(MatrixRm& data) override
    {
     ...
    }
}

Теперь я хотел бы передать любой из этих классов в функцию или конструктор другого класса. Но в настоящее время я не могу понять, как это сделать, не указав конкретный тип.

Вот как я это себе представляю:

void someFunction(Dataset* dataset)
{
    //do something with the specialization
}

В Visual Studio появляется следующее сообщение об ошибке:

отсутствует список аргументов для шаблона класса «Набор данных»

Мне имеет смысл, почему это не разрешено, но есть ли способ обойти это?

Ответы [ 3 ]

1 голос
/ 04 ноября 2019

Одна идиома - предполагать, что someFunction будет вызываться только с объектом Dataset и обрабатывать Dataset как параметр шаблона, как в:

template<class Dataset>
void someFunction(Dataset dataset){
    // ...
}

Конечно, это решениебудет генерировать различный код для каждой специализации someFunction для каждого переданного ему уникального типа.

Эта идиома может быть реализована более безопасным способом с использованием некоторого шаблона шаблона метапрограммирования, например:

#include <type_traits>

template<class T>
struct is_dataset: std::false_type{};

template<class T1, class T2>
struct is_dataset<Dataset<T1, T2>>: std::true_type{};

template<class Dataset>
std::enable_if_t<is_dataset<Dataset>::value, void>
someFunction(Dataset dataset){
    // ...
}

Этот код определяет метафункцию is_dataset для эффективного выполнения проверки времени компиляции, если переданный шаблон Dataset фактически является Dataset объектом.

Как вам кажется, Dataset*не является реальным типом (или даже неполным типом). Он просто предоставляет интерфейс для построения реального типа (например, Dataset<std::string, std::string>).

1 голос
/ 04 ноября 2019

Вы также можете объявить функцию как шаблон:

template<class T1, class T2>
void someFunction(Dataset<T1, T2>* dataset)
{
    //do something with the specialization
}

void foo() {
    InMemoryDataset inMemory;
    someFunction(&inMemory); 
    // Will call someFunction<MatrixRm, MatrixRm>(Dataset<MatrixRm, MatrixRm> *)

    OnlineDataset online;
    someFunction(&online); 
    // will call someFunction<std::string, std::string>(Dataset<std::string, std::string> *)
}
1 голос
/ 04 ноября 2019

В этом конкретном случае вы можете просто использовать не шаблонный базовый класс для вашего интерфейса:

class Dataset {
public:
   virtual void doSomething(MatrixRm& data) = 0;
};

template<typename T1, typename T2> class Dataset_impl : public Dataset
{
protected:
   std::vector<std::pair<T1, T2> > _data_buffer;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...