Jump to content
  • Advertisement
Sign in to follow this  
King of Men

Concatenation giving me a warning message

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am probably trying to be a little too clever for my own good, but what the heck, it's fun. I'm trying to define <, >, <=, and >= for a class of mine, and though it would be efficient to do it as a macro, like so : Edit : Gah, I cannot figure out how to make this stupid thing put in \ at the end of a line without actually removing the newline. Please consider each line of my 'define' to have a backslash at the end, ok?
#define FormationOperator(x) bool Formation::operator##x (Formation f) {
  switch (whichSort) { 
    case SCOUT:
      return getScouting() x f.getScouting();
    case SPEED :
    default :
      return getSpeed() x f.getSpeed();  
  }
}

FormationOperator(>)
FormationOperator(>=)
FormationOperator(<)
FormationOperator(<=)


Now, this seems to compile, but the preprocessor gives me warnings of a cryptic nature: Formation.cc:348:20: warning: pasting "operator" and ">" does not give a valid preprocessing token Formation.cc:349:21: warning: pasting "operator" and ">=" does not give a valid preprocessing token Formation.cc:350:20: warning: pasting "operator" and "<" does not give a valid preprocessing token Formation.cc:351:21: warning: pasting "operator" and "<=" does not give a valid preprocessing token I do not understand why 'operator<=' should not be a valid preprocessing token. What are the requirements?

Share this post


Link to post
Share on other sites
Advertisement
Come to think of it, I have another question along these lines. Let's say I've managed to define these operators for class Foo. Now, if I do this:


std::vector<Foo*> myFooPointerList;
// Fill up the list
sort(myFooPointerList.begin(), myFooPointerList.end());


will my operators get used in comparing the Foo pointers, or will my list get sorted by the numerical value of the addresses?

Share this post


Link to post
Share on other sites
Quote:
Original post by King of Men
Come to think of it, I have another question along these lines. Let's say I've managed to define these operators for class Foo. Now, if I do this:


std::vector<Foo*> myFooPointerList;
// Fill up the list
sort(myFooPointerList.begin(), myFooPointerList.end());


will my operators get used in comparing the Foo pointers, or will my list get sorted by the numerical value of the addresses?


I'm not sure about your first post, but that sorting will definitely not work like you want. It'll do some kind of sorting according to the pointer address. You'll have to give it a function, like so:



struct myFooPointerSorter {
bool operator()(myFooPointer *f1, myFooPointer *f2) {
if(f1 < f2) return true;
}
};

sort(myFooPointerList.begin(), myFooPointerList.end(), myFooPointerSorter());

Share this post


Link to post
Share on other sites
Quote:
Original post by King of Men
What are the requirements?

The primary requirement is that you have a reason to use a macro in the first place.

As to your other question, ignore containers. How does (int* < int*) behave?

CM

Share this post


Link to post
Share on other sites
A little test snippet for int* tells me that < compares pointer addresses unless you dereference the pointers. It seems to me that this means there is a typo in okonomiyaki's post;

if(f1 < f2) return true;

should be

if (*f1 < *f2) return true;

Right?

Share this post


Link to post
Share on other sites
Quote:
Original post by King of Men
A little test snippet for int* tells me that < compares pointer addresses unless you dereference the pointers. It seems to me that this means there is a typo in okonomiyaki's post;

if(f1 < f2) return true;

should be

if (*f1 < *f2) return true;

Right?

Yes.

CM

Share this post


Link to post
Share on other sites
1) You should, assuming normal circumstances, be passing Formations by const reference to relational operators, not by value.

2) Similarly, it makes sense to define the operator as a free function. You get extra conversions for free this way. You should prefer free functions for most binary function overloads (except assignment). Arithmetic binary operators can often be implemented in terms of the corresponding unary immediate operator, which would be a member function.

3) To get the real benefit of code reuse here, you would probably do better to implement a "3-way comparison" ala strcmp(), and then just make the operators wrap that.

4) You're depending on some internal state of the left-hand object to decide how to compare the two objects. That's likely to cause huge problems. Consider sorting a container of Formations which have different states. Inconsistencies abound. Instead, use comparators.

Something like this should do the trick:

template <typename T, typename CMP>
struct ComparatorBase {
bool operator<(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) < 0;
}
bool operator<=(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) <= 0;
}
bool operator>(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) > 0;
}
bool operator>=(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) >= 0;
}
bool operator==(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) == 0;
}
bool operator!=(const T& lhs, const T& rhs) {
return CMP::cmp(lhs, rhs) != 0;
}
}

struct Scouting {
static int cmp(const Formation& lhs, const Formation& rhs) {
// assuming each returns an int.
// This gives a negative value when lhs < rhs,
// 0 when equal, positive when lhs > rhs.
return lhs.scouting - rhs.scouting;
}
};

struct Speed {
static int cmp(const Formation& lhs, const Formation& rhs) {
// assuming each returns an int.
// This gives a negative value when lhs < rhs,
// 0 when equal, positive when lhs > rhs.
return lhs.speed - rhs.speed;
}
};

class Formation {
typedef ComparatorBase<Formation, Scouting> ScoutingComparator;
friend class Scouting;
friend class ScoutingComparator;
typedef ComparatorBase<Formation, Speed> SpeedComparator;
friend class Speed;
friend class SpeedComparator;
// everything else here
};

std::sort(myFormations.begin(), myFormations.end(),
Formation::SpeedComparator());

Share this post


Link to post
Share on other sites
Quote:
Original post by King of Men
A little test snippet for int* tells me that < compares pointer addresses unless you dereference the pointers. It seems to me that this means there is a typo in okonomiyaki's post;

if(f1 < f2) return true;

should be

if (*f1 < *f2) return true;

Right?


I apologize, yes you are correct.

Zahlman - excellent points!

Share this post


Link to post
Share on other sites
Quote:
I do not understand why 'operator<=' should not be a valid preprocessing token. What are the requirements?

The syntax defines what preprocessing tokens are, and they don't include strings like "operator>" - that's two tokens ("operator" and ">"). And it says "If the result [of concatenation with ##] is not a valid preprocessing token, the behavior is undefined", which is why the compiler is warning about it. But because "operator>" is meant to be two tokens, you can just do "#define FormationOperator(op) ... operator op ..." and it'll work the way you wanted.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
1) You should, assuming normal circumstances, be passing Formations by const reference to relational operators, not by value.


Good point.

Quote:
2) Similarly, it makes sense to define the operator as a free function. You get extra conversions for free this way. You should prefer free functions for most binary function overloads (except assignment). Arithmetic binary operators can often be implemented in terms of the corresponding unary immediate operator, which would be a member function.


I don't understand what you mean by 'extra conversions for free'; could you explain?

Quote:
3) To get the real benefit of code reuse here, you would probably do better to implement a "3-way comparison" ala strcmp(), and then just make the operators wrap that.


That would be simpler, yes. Or just define the <, and define the others in terms of it.

Quote:
4) You're depending on some internal state of the left-hand object to decide how to compare the two objects. That's likely to cause huge problems. Consider sorting a container of Formations which have different states. Inconsistencies abound.


Ah, but no - whichSort is a static member variable, it cannot differ between Formations.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!