I'm having trouble overloading the operator< for a class that I want to use as a key for an stl map.

It works fine for a comparison test, but when I try to use the std::map.find() function I get an error: binary '<' : no operator found which takes a left-hand operand of type 'const StrategyKey' (or there is no acceptable conversion)

I've posted my test code below. Note, it is the commented out line that causes the error.

class StrategyKey
{
public:
	StrategyKey(){}
	~StrategyKey(){}

	StrategyKey(const char* a, const char* b):
	str_A(a),
		str_B(b)
	{
	}

	bool operator< (const StrategyKey& stratKey)
	{
		if (stratKey.str_A < this->str_A)
		{
			return false;
		} 
		else if (stratKey.str_A == this->str_A && stratKey.str_B < this->str_B)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	bool operator== (const StrategyKey& StratKey)
	{
		if (StratKey.str_A == this->str_A && StratKey.str_B == this->str_B)
		{
			return true;
		}
		else
			return false;
	}

	std::string str_A;
	std::string str_B;
};

int _tmain(int argc, _TCHAR* argv[])
{
	StrategyKey aKey("about", "apples");
	StrategyKey bKey("before", "bananas");

	map<StrategyKey, int> myMap;

	//myMap.find(aKey);


	if (aKey < bKey)
	{
		cout << "aKey < bKey" << endl;
	}
	else
		cout << "aKey !< bKey" << endl;

	cin.get();
	return 0;
}

First of all, operators like comparison operators should usually be implemented as friend functions, not as member functions. In this case, that is not the problem.

The problem is that your member functions for operators < and == both take a const reference (which is correct), but the member functions are not marked as const themselves. Because member functions are called on an object of the class. If that object happens to be marked as 'const', then it should not be modified, which means that only member functions which don't modify the object can be called, and so, you need to mark those member functions which don't modify the object with the keyword 'const' at the end of the function prototype. As so:

bool operator< (const StrategyKey& stratKey) const //notice 'const' here.
	{
	  //..
        }

	bool operator== (const StrategyKey& StratKey) const //notice 'const' here.
	{
	  //..
	}

The error you are getting is simply because the function find() in map is marked as const, and thus, the constness propagates to all its elements, which means only const member functions can be called on them, which excluded your operator overloads (since they were not const).

Usually, the idiomatic way of implementing this is as follows, using friend functions instead:

class StrategyKey
{
public:
   //...
	friend bool operator< (const StrategyKey& stratKey1, const StrategyKey& stratKey2) 
	{
	  //..
        }

	friend bool operator== (const StrategyKey& StratKey1, const StrategyKey& StratKey2)
	{
	  //..
	}
  //...
}

Excellent! Thank you.

With regard to friend functions, would their definition then usually occur outside of the class scope?

>>would their definition then usually occur outside of the class scope?
Not necessarily. Operators can be non-friend as well if access to private members is not necessary. They can be defined outside the class declaration if they seem too long to remain in the declaration. Often people use the friend keyword just so that the implementation can be put in the declaration (even if private member access is not needed), when the function is very small it is sometimes nicer to have it in the declaration. But this is all just a matter of taste (however, when it comes to class templates, it is usually more natural to have them in the class declaration).

The main idea here is that free-functions should be preferred to member functions for essentially all operators that allow them. This is because of overload resolution, function hiding, and other considerations. Just get in the habit of overloading operators as free-functions (friend or not, in-declaration or not).

Edited 5 Years Ago by mike_2000_17: n/a

Comments
will do
This question has already been answered. Start a new discussion instead.