• 9
• 9
• 10
• 9
• 10

Vector cast

This topic is 1001 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hello. Its is possible to cast a vector to a function ? For example I have a function Add that takes a reference to Vector data type. Add(Vector &data).

When I construct some vectors based on variables I always have to make a temporary objects, fill it with the data and pass it to the function.

Vector temp; temp.x = variable; Add(temp). I want to do something like Add(Vector(1,2,3)); or Add(Vector(var1,var2,var3)); How should I aproach this ? Its better to add more overloaded functions for every type of data I will possible send?

Share on other sites

Assuming C++...

Ensure that your Vector class has a constructor that fits. In your example, it seems like it would Vector::Vector(int x, int y, int z). Doing that should make it work.

Sample code that compiles (in Visual Studio, your mileage may vary -- see Mona2000's reply):

class Vector
{
public:
Vector(int a, int b, int c) { x = a; y = b; z = c; }
private:
int x, y, z;
};

{
//Stuff here
}

void test()
{
}

Edited by Lactose!

Share on other sites

You mean sample code that compiles only if you have Microsoft language extensions enabled (i.e. no /Za).
Else you're gonna have to change that to a const reference, like Brother Bob already mentioned.

Good catch. Thanks for the correction :)

Share on other sites

If we're talking about a 2/3/4 dimensional vector class that has a x/y/z/w components, then i'd pass it by value if i'm not modifying it. Works the same as a const reference, and since it's a temporary, you really don't need it to be a reference to anything, const or not.

Share on other sites
Like std::min() and std::max()? (C++11 lets them take an arbitrary number of parameters)
int smallestValue = std::min({valueA, valueB, valueC, valueD});

Ideone.com

Here's an example in my own code: (averaging an arbitrary number of points)
cPointF centerOfQuad = cPointF::AveragedPoint({corners.topLeft, corners.topRight, corners.bottomRight, corners.bottomLeft});


Here's the implementation:
//Returns a point that is the average between two or more points.
static Point AveragedPoint(const std::vector<Point> &points)
{
Point result;

for(const Point &point : points)
{
result += point;
}

//Average the result.
if(points.empty() == false)
{
result /= Point(points.size(), points.size());
}

return result;
}

Here's another example: (rotating an arbitrary number of points around a center)
cPointF::RotateAround(rect.Center(), rotation, {corners.topLeft, corners.topRight, corners.bottomRight, corners.bottomLeft});

And the implementation: (especially interesting, because it has to manipulate the arbitrary number of parameters - they are output also, not just input).
//Rotates an arbitrary amount of points around a shared center.
static void RotateAround(const Point &center, float rotation, std::vector<std::reference_wrapper<Point>> points)
{
//Calculate and apply the rotation.

//Rotate each point individually.
for(auto &point : points)
{
priv_Point_RotateAround_RotatePoint(point, center, sine, cosine);
}
}

static void priv_Point_RotateAround_RotatePoint(Point &point, const Point &center, float sine, float cosine)
{
//Move the problem domain to make the center be (0,0), which is what we'll rotate around.
float offsetX = static_cast<float>(point.x - center.x);
float offsetY = static_cast<float>(point.y - center.y);

//Calculate the new offset.
point.x = static_cast<Point::value_type>((offsetX * cosine) - (offsetY * sine));
point.y = static_cast<Point::value_type>((offsetX * sine)   + (offsetY * cosine));

//Apply the center to the new offset and return.
point += center;

return;
}

The standard library uses std::initializer_list. For simplicity's sake, I just use std::vector. By 'simplicity' I mean... I haven't actually looked into how to use std::initializer_list yet.  Edited by Servant of the Lord

Share on other sites

The standard library uses std::initializer_list. For simplicity's sake, I just use std::vector. By 'simplicity' I mean... I haven't actually looked into how to use std::initializer_list yet.

It's kind of like std::array's weird more-restricted cousin You avoid narrowing casts, is essentially a temporary (and as such is const and immutable), and the only things you can do with it are get its size and iterate over it (can't even use random-access).

By using initializer_list you'd end up with faster code, as it (likely) won't have vector's allocation/deallocation overhead. Edited by SmkViper

Share on other sites

Thanks for the answers. I have another questions. I have several structs for a Vector. For example a struct that has position, another that has more elements and its inherited from the first one and so on and I have the same system for Vertex structure . I have several functions that deal with Vertex data but I cant bind to one single struct type to pass in the parameters of the function because I may pass a different one. For example I have meshes that use a Vertex with only the position and some meshes that have position, texture and normals components. And I have a function that creates AABB from a mesh like CreateAABB(Vertex_pos &data). How should I handle different objects types that are passed in the function (objects defined by different structs but I need to access the data that all structs have: the position vector) ? Should I create a more generic function? Should I use pointer cast ? (assuming all Vertex structure definition are inherited from a simple one to the complex one).

Now I'm casting like this:

void CreateCollisionAABB(XVector<Vertex_pos> &data) {

...

}

instances.data is  type struct Vertex_nm that is inherited from Vertex_pos and has additional elements.

CreateCollisionAABB((XVector<Vertex_pos> &)instances[i].data);


Edited by Azzazelus

Share on other sites

I have several structs for a Vector. For example a struct that has position, another that has more elements and its inherited from the first one and so on

It sounds like you might be abusing inheritance where composition might be a better choice.

Could you show us an example we can bash? Uh, I mean critique?

[Edit:] I missed part of your post. See my next post for the follow-up.

I have several functions that deal with Vertex data but I cant bind to one single struct type to pass in the parameters of the function because I may pass a different one.

If inheritance is the proper choice, then you'll want to take references or pointers. Your CreateCollisionAABB for example, could take a vector of references (std::reference_wrapper) like I showed for the 'RotateAround()' function in my previous post.

To convert a vector of Type to a vector of references to that type, I do this:

template<class BaseType, class ContainerType>
std::vector<std::reference_wrapper<const BaseType>> RefWrapAsVector(const ContainerType &container)
{
//Create a vector of std::reference_wrappers wrapping 'BaseType'.
return std::vector<std::reference_wrapper<const BaseType>>(std::begin(container), std::end(container));
}


And use it like this:

void ForceAnimalsToTalk(const std::vector<std::reference_wrapper<const Animal>> &animals)
{
for(const Animal &animal : animals)
{
animal.Talk();
}
}

int main()
{
//Really just an excuse to add moar cats to teh code.
std::vector<Cat> myCats = {Cat("Meow"), Cat("Purr"), Cat("Meowmeow"), Cat("*yawns adorably*")};

ForceAnimalsToTalk(RefWrapAsVector<Animal>(myCats));

return 0;
}


Ideone example

But if inheritance isn't the proper choice for your types, then you probably just want a templated function.

Probably something like this:

template<typename VertexType>
BoundingBox CreateCollisionAABB(const XVector<VertexType> &data)
{
BoundingBox boundingBox;

for(const VertexType &vertex : data)
{
//Will work for any class that has 'x'/'y'/'z' members,
//as long as the types of those members are compatible (castable) with 'ExtendToContains()'
boundingBox.ExtendToContain(vertex.x, vertex.y, vertex.z);
}

return boundingBox;
}


Alternatively, you can go template-crazy, and use vectors of arbitrary types, and take pointer-to-members to retrieve the values, that way the parameters can be of arbitrary variable names. That's pushin' it though.

Or, if your data is POD, you can just take a pointer of bytes, and a stride, and cast internally. Not type-safe, so the burden is on the caller to make sure things are correct, but it is an option.

Edited by Servant of the Lord