问题
实现一个适用于标量和数组的复制函子“接口”。
CopyFunctor::operator()(T& dest, const T& src);
作为一个例子,我想概括一个排序函数来处理元素数组和“内联”数组的数组。
template <typename T, typename CopyFunctor> sort(T array[]);
int array_of_elements[] = {7, 3, 5, 2};
sort(array_of_elements);
// after sorting: {2, 3, 5, 7}
int array_of_arrays[] = { 3, 1, 2, 4, 7, 6, 5, 8};
// inlined arrays are: {3, 1}, {2, 4}, {7, 6}, {5, 8}
// these 'inlined' arrays are fixed-sized
// after sorting using first element as key: { 2, 4, 3, 1, 5, 8, 7, 6}
// thus, the second element should be moved with the first element
在 sort(T array[]) 内部,为了将元素(或元素组)从位置 i 交换到位置 j,我们可以以完全相同的方式调用函子,无论 a 是元素数组还是“内联数组”数组':
template <typename T, typename CopyFunctor> sort(T array[], CopyFunctor copy) {
// ...
// swap a[i] and a[j]
copy(b, a[i]);
copy(a[i], a[j]);
copy(a[j], b);
// ...
}
这里 b 要么是一个标量,要么是一个大到足以容纳 a 内的一个“内联”数组的数组。(对于这个例子,我可能想要一个交换函子,但在我更复杂的用例中,我需要一个复制函子。)
假设
一旦内联数组的数组被初始化,它就永远不会被调整大小。
示例代码
#include <cstdio>
#include <cstring>
using namespace std;
template <typename T>
struct ScalarSetter {
void operator()(T& a, const T& b) const {
a = b;
}
};
template <typename T>
struct ArraySetter {
size_t _n;
ArraySetter(size_t n) : _n(n) {}
void operator()(T& a, const T& b) const {
std::memcpy(&a, &b, sizeof(T)*_n);
}
};
int main(int argc, char* argv[]) {
{
ScalarSetter<float> copy;
float a = 1.0;
float b = 2.0;
copy(a, b);
printf("a = %f\n", a);
/* output:
* a = 2.00000
*/
}
{
size_t n = 3;
ArraySetter<float> copy(n);
float c[] = {.1, .2, .3, .4};
float d[] = {.4, .5, .6, .7};
copy(c[0], d[0]);
for (size_t i = 0; i < n+1; ++i) {
printf("c[%d] = %f\n", i, c[i]);
}
/* output:
* c[0] = 0.400000
* c[1] = 0.500000
* c[2] = 0.600000
* c[3] = 0.400000
*/
}
return 0;
}
由于我实际上使用的是 Cuda/C++,我或多或少被迫使用内联数组。
上面的示例代码编译、运行并通过了 valgrind 内存测试。但是我觉得在 ArraySetter::operator()(...) 中找到指向输入参数的指针有点不舒服。
(编辑:我认为如果内联数组不连续,代码会中断......对(动态)分配的数组的连续性有任何保证吗?)
是否有另一种方法可以实现与标量和数组一起使用的一致复制函子“接口”?