我有一个Vector3
结构,由三个double类型的成员值组成。
struct Vector3 {
double x, y, z;
};
我需要将对该结构实例的引用传递给一个接受float类型数组的函数。我无法更改其接受的类型。
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();
}
}
答案 0 :(得分:5)
临时数组可以隐藏在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));
答案 1 :(得分:4)
您的第一个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
,那真是令人讨厌。
答案 2 :(得分:1)
一种可能性是创建一个具有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 ) );
请参阅工作版本here。
答案 3 :(得分:0)
基于Martin的答案(更好格式的新答案):为此功能编写模板化版本:
template<typename Func>
void wrapper(Func f, const Vector3d &value){
const float temp[] = {(float)MyVector.x, (float)MyVector.y, (float)MyVector.z);
f(temp);
}
对于多种类型,如果它们相似,也可以做一些模板处理,但这取决于您拥有的类型。
上面的免责声明未经测试,我现在在移动设备上。