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

时间:2019-11-22 09:53:17

标签: c++ arrays

我有一个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();
  }
}

4 个答案:

答案 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);
}

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

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