我希望创建一个可以多态地在浮点数组和双精度数组之间转换的类。也就是说,相关的实例(由<double>
or参数化<float>
)和通过float*
ordouble*
的决定是在运行时决定的,而不是静态的。
作为另一个问题的建议答案,但根据此答案进行了修改(因为我知道不可能在类中完全专门化成员函数模板),BaseDest
提供简单的重载成员函数的纯虚拟基类被子类化以定义DestImpl<T>
. 我使用这个基类来维护DestImpl<T>
实例的动态集合,其中包含不同的T
. 此类提供assign()
成员函数的显式重载;一个用于 a double *
,另一个用于 a float *
。这个想法是,在运行时,BaseDest::assign()
通过多态指针或引用调用,这反过来又assign()
在DestImpl<T>
.
现在,重要的是数组的非指针类型匹配 T in DestImpl<T>
,fast_copy()
调用一个函数(可能是一个 memcpy),并且当类型不匹配一个较慢的静态强制逐项复制时执行。因此,assign()
成员函数将其卸载到模板仿函数。这个函子有两种特化——一种是函子的类型参数匹配的类型DestImpl<T>
(因此调用快速复制),另一种是捕获所有其他情况(并调用慢速复制)的回退。
但是,我无法编译以下代码。注释显示了编译器错误和警告出现的位置——我怀疑它们是相关的。我不明白的是为什么第二个专业化apply_helper
无法实例化为apply_helper<double>
.
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
void assign(const double * v, size_t cnt) {
assign_helper<T>()(v, cnt);
}
void assign(const float * v, size_t cnt) {
assign_helper<T>()(v, cnt); // ERROR: no matching function for call to object of type 'assign_helper<double>'
}
protected:
template <typename U>
struct assign_helper {
void operator()(const U * v, size_t cnt) {
for (size_t i = 0; i < cnt; ++i) {
//slow_copy(v[i]);
}
}
};
template <typename U>
struct assign_helper<T> { // WARNING: Class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used
void operator()(const T * v, size_t cnt) {
//fast_copy(v, cnt);
}
};
};
void test() {
DestImpl<double> d; // error mentioned above appears when this is present
}
编辑:这似乎确实有效 - 将assign_helper
结构(现在是一个类)移出DestImpl<T>
类定义。我不确定这是不是正确的方法,但到目前为止它似乎确实有效:
// slow copy between different types
template <typename T, typename U>
class assign_helper {
public:
void operator()(const U *v, size_t cnt) {
// slow copy
}
};
// fast copy between same types
template <typename T>
class assign_helper<T, T> {
public:
void operator()(const T * v, size_t cnt) {
// fast copy
}
};
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
virtual void assign(const double * v, size_t cnt) {
assign_helper<T, double>()(v, cnt);
}
virtual void assign(const float * v, size_t cnt) {
assign_helper<T, float>()(v, cnt);
}
};