将模板传递给函数而不指定具体类型

Passing template to a function without specifying concrete type

本文关键字:类型 函数      更新时间:2023-10-16

是否可以在不指定具体类型的情况下将模板传递给函数?

我有一个基类,它是一个模板,有两种不同的专业化

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中,我收到以下错误消息:

类模板的

参数列表"数据集";缺少

对我来说,为什么不允许这样做是有道理的,但有什么办法吗?

您也可以将函数声明为模板:

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> *)
}

在这种特定情况下,您可以为接口使用一个非模板基类:

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;
};

一个习惯用法是假设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>(提供了一个接口。