3
votes

I try to use GLM vector classes in STL containers. No big deal as long as I don't try to use <algorithm>. Most algorithms rely on the == operator which is not implemented for GLM classes.

Anyone knows an easy way to work around this? Without (re-)implementing STL algorithms :(

GLM is a great math library implementing GLSL functions in c++

Update

I just found out that glm actually implements comparison operators in an extension (here). But how do i use them in stl?

Update 2

This question has been superseded by this one: how to use glm's operator== in stl algorithms?

3
I am not sure which one of the answers is more of a hack ... - fho
Neither of them are hacks. They're both perfectly fine and idiomatic solutions. Just keep in mind that the operators effectively extend the type: if you define an operator==, all clients will assume it is the way to test for equality. If it is only for use in STL algorithms, a functor might be a better way to go. That might be ok for equality (although you may sometimes want to use a variable epsilon), but it's probably a bad idea for operator<, since there's no obvious way to define if a vector is "less than" another, so when that is needed, I'd go with a functor. - jalf

3 Answers

5
votes

Many STL algorithms accept a functor for object comparison (of course, you need to exercise special care when comparing two vectors containing floating point values for equality).

Example:

To sort a std::list<glm::vec3> (it's up to you whether sorting vectors that way would make any practical sense), you could use

std::sort(myVec3List.begin(), myVec3List.end(), MyVec3ComparisonFunc)

with

bool MyVec3ComparisonFunc(const glm::vec3 &vecA, const glm::vec3 &vecB)
{
 return vecA[0]<vecB[0] 
        && vecA[1]<vecB[1] 
        && vecA[2]<vecB[2];
}

So, thankfully, there is no need to modify GLM or even reinvent the wheel.

3
votes

You should be able to implement a operator== as a stand-alone function:

// (Actually more Greg S's code than mine.....)

bool operator==(const glm::vec3 &vecA, const glm::vec3 &vecB) 
{ 
   const double epsilion = 0.0001;  // choose something apprpriate.

   return    fabs(vecA[0] -vecB[0]) < epsilion   
          && fabs(vecA[1] -vecB[1]) < epsilion   
          && fabs(vecA[2] -vecB[2]) < epsilion;
} 
2
votes

James Curran and Greg S have already shown you the two major approaches to solving the problem.

  • define a functor to be used explicitly in the STL algorithms that need it, or
  • define the actual operators == and < which STL algorithms use if no functor is specified.

Both solutions are perfectly fine and idiomatic, but a thing to remember when defining operators is that they effectively extend the type. Once you've defined operator< for a glm::vec3, these vectors are extended to define a "less than" relationship, which means that any time someone wants to test if one vector is "less than" another, they'll use your operator. So operators should only be used if they're universally applicable. If this is always the one and only way to define a less than relationship between 3D vectors, go ahead and make it an operator.

The problem is, it probably isn't. We could order vectors in several different ways, and none of them is obviously the "right one". For example, you might order vectors by length. Or by magnitude of the x component specifically, ignoring the y and z ones. Or you could define some relationship using all three components (say, if a.x == b.x, check the y coordinates. If those are equal, check the z coordinates)

There is no obvious way to define whether one vector is "less than" another, so an operator is probably a bad way to go.

For equality, an operator might work better. We do have a single definition of equality for vectors: two vectors are equal if every component is equal.

The only problem here is that the vectors consist of floating point values, and so you may want to do some kind of epsilon comparison so they're equal if all members are nearly equal. But then the you may also want the epsilon to be variable, and that can't be done in operator==, as it only takes two parameters.

Of course, operator== could just use some kind of default epsilon value, and functors could be defined for comparisons with variable epsilons.

There's no clear cut answer on which to prefer. Both techniques are valid. Just pick the one that best fits your needs.