将模板传递给函数而不指定具体类型
Posted
技术标签:
【中文标题】将模板传递给函数而不指定具体类型【英文标题】:Passing template to a function without specifying concrete type 【发布时间】:2019-11-04 18:06:06 【问题描述】:是否可以在不指定具体类型的情况下将模板传递给函数?
我有一个基类,它是一个模板和它的两个不同的特化。下面是一个基类的例子:
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)
?
【参考方案1】:
你也可以将函数声明为模板:
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> *)
【讨论】:
谢谢! someFunction 将对这两种类型执行相同的操作。我使用模板只是为了区分数据在数据集中的存储方式。这样,我必须实现两个功能做同样的事情,对吧? @Bastian 抱歉回答晚了,是的,你只实现了一次someFunction
。【参考方案2】:
在这种特定情况下,您可以只为您的界面使用非模板基类:
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;
;
【讨论】:
为什么有人反对这个?我认为这很聪明:) @Frank: ideone.com/w7bjsz 这样他就无法将 Dataset 类型传递给 foo 函数。 @nomanpouigt OP 的数据集已经很抽象了。所以他们一开始就不能这样做【参考方案3】:一个习惯用法是假设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>
)提供了一个接口。
【讨论】:
谢谢!您的解决方案有您所说的一个缺点……元编程会降低性能,对吗?在我的情况下,这还不够。 您应该不会注意到任何运行时损失。唯一的缺点是(可能)过多的代码翻译(即代码膨胀)。对于大量Dataset
规范,您可能注意到编译时间增加。以上是关于将模板传递给函数而不指定具体类型的主要内容,如果未能解决你的问题,请参考以下文章