创建一个函数来转换数组元素的类型并返回数组的地址



>我有一个Vector3结构,由三个双精度类型的成员值组成。

struct Vector3 {
double x, y, z;
};

我需要将对这个结构的实例的引用传递给一个接受浮点型数组的函数。我无法更改它接受的类型。

void foo(const float *value);

我可以创建一个临时数组来更改类型并将其传递给函数:

Vector3 MyVector = Vector3(1, 2, 3);
const float temp[] = {(float)MyVector.x, (float)MyVector.y, (float)MyVector.z);
foo(temp);

虽然这有效,但我需要经常执行此操作,并且我想避免它造成的视觉混乱。

有没有一种好方法来定义一个函数来转换成员变量的类型并将其传递给foo?这是我尝试过的:

struct Vector3 {
...
float* getPointer() {
static float temp[3] = {x, y, z};
return temp;
}
}
struct Vector3 {
...
float* getPointer() {
std::vector<float> temp = {x, y, z};
return temp.data();
}
}

临时数组可以隐藏在class中:

class As_float_ptr {
public:
As_float_ptr(const Vector3& vec) 
: data{(float)vec.x, (float)vec.y, (float)vec.z}
{ }
operator const float*() { return data; }
private:
const float data[3];
};
Vector3 vec;
foo(As_float_ptr{vec});

临时对象As_float_ptr只有在foo()返回后才会被销毁,因此将指向其数据成员的指针data[3]传递到foo()中是安全的。

如果要支持多种存储类型,可以执行以下操作:

template<std::size_t size>
class As_float_ptr {
public:
As_float_ptr(const Vector2& vec) : data{(float)vec.x, (float)vec.y} {
static_assert(size == 2);
}
As_float_ptr(const Vector3& vec) : data{(float)vec.x, (float)vec.y, (float)vec.z} {
static_assert(size == 3);
}
operator const float*() { return data; }
private:
const float data[size];
};
As_float_ptr(const Vector2&) -> As_float_ptr<2>;
As_float_ptr(const Vector3&) -> As_float_ptr<3>;
Vector2 vec2;
foo(As_float_ptr{vec2});
Vector3 vec3;
foo(As_float_ptr{vec3});

此代码使用 C++17 推导指南从构造函数参数的类型推导出size模板参数。如果 C++17 不可用,则可以改用make类型函数:

As_float_ptr<2> make_float_ptr(const Vector2& vec) {
return As_float_ptr<2>{vec};
}
As_float_ptr<3> make_float_ptr(const Vector3& vec) {
return As_float_ptr<3>{vec};
}
foo(make_float_ptr(vec2));
foo(make_float_ptr(vec3));

你的第一个getPointer成员函数(带有静态数组(是合法的,但非常非常危险 - 它不是线程安全的。

一旦您尝试引用函数结果,您的第二次尝试(创建一个临时向量并返回 .data((((就是 UB(临时将被销毁,.data(( 返回的指针将不再有效((。

另一个明显的解决方案是提供foo过载 .

void foo(const Vector3& value) {
const float temp[] = {(float)value.x, (float)value.y, (float)value.z);
foo(temp);
}

但这只有在只有少数功能的情况下才有效,例如foo. 如果有多个功能和多种类型,例如Vector3,那将变得非常讨厌。

一种可能性是创建一个具有 3 个浮点数的结构,该结构转换为float const*

struct Float3{
operator float const*(){ return values; }
float values[3];
};

并从转换函数按值返回该值。

Float3 to_float3( Vector3 const& d ){
return { { (float)d.x, (float)d.y, (float)d.z} };
}

然后可以像这样使用此函数:

Vector3 vec{};
foo( to_float3( vec ) );

在此处查看工作版本。

基于马丁的答案(新答案以获得更好的格式(: 为此函数编写模板化版本:

template<typename Func>
void wrapper(Func f, const Vector3d &value){
const float temp[] = {(float)MyVector.x, (float)MyVector.y, (float)MyVector.z);
f(temp);
}

对于多个类型,如果它们相似,您也可以执行一些模板,但这取决于您拥有的类型。

上面的免责声明未经测试,我现在在移动设备上。

最新更新