Error C2678?

So I have the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<typename T1, typename T2> class Pair
{
public:
	T1 a; T2 b;

	Pair() {}
	Pair(const T1& a, const T2& b) : a(a), b(b) {}
	Pair(const Pair<T1, T2>& other) : a(other.a), b(other.b) {}

	void operator=(const Pair<T1, T2>& other)
	{ a = other.a; b = other.b; }

	bool operator==(const Pair<T1, T2>& other)
	{ return (a == other.a && b == other.b); }

	bool operator!=(const Pair<T1, T2>& other)
	{ return (a != other.a || b != other.b); }
};

typedef Pair<int, int> IP;

int main()
{
	std::vector<IP> a1, a2;
	a1.push_back(IP(1, 42));
	a2.push_back(IP(1, 42));

	printf("%i\n", (a1 == a2));
}


Now, this code crashes, giving me the following error message:

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const Pair<int,int>' (or there is no acceptable conversion)

I have no idea why it's doing this, and I would appreciate anyone who could shed some light on this matter.

(If it matters, I am using Visual Studio Express 2013 as my IDE.)
You are comparing a vector to a vector, not a pair to a pair.
... Err, well, yes, obviously. std::vector should have a built-in operator== function, that's why I'm wondering why this error occurs.
Member operator== is not the same as non-member operator== - specifically, the member version does not allow implicit casts on the left hand side.
... What do you mean?
... That really doesn't help me any. What does that have to do with this error?
As your error message states, your operator cannot be invoked on constant Pair in the left side. You explicitely marked it as changing left operand.
Be const correct:
bool operator==(const Pair<T1, T2>& other) const // ← There and in some other places  
Or, even better, define your operator as non-member.
Last edited on
All right; if I understand this correctly, the following should be true:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Class
{
public:
	int val;

	void operator=(const Class& other)
	{ val = other.val; }
	/* Should not be const as a value is modified (?) */

	bool operator==(const Class& other) const
	{ return (val == other.val); }
	/* Should be const as no value is modified (?) */
};

class ClassManager
{
public:
	Class c;

	bool operator==(const Class& other) const
	{ return (c == other); }

	/*
	Since "operator==" in <Class> was declared const,
	this can be called on a const object (?)
	*/
};


However, what about the following:
1
2
3
bool operator==(const Class& rhs, const Class& lhs)
{ return (rhs.val == lhs.val); }
/* Is this a correct implementation? Should it be const or non-const? */
Last edited on
Non-member functions cannot have qualifiers. In other words, this is invalid code if not in a class:
1
2
3
void f() const
{
}
Last edited on
Ah, I see. In that case, which should I use? If I understand correctly, having a non-member operator overloaded means that you can use String s = "Hello" + "World", not only String s = String("Hello") + "World", or something to that effect. Is this correct?

If so, is this the only advantage having a non-member versus a member o.o.? Are there any disadvantages?
RotatingAxis wrote:
If I understand correctly, having a non-member operator overloaded means that you can use String s = "Hello" + "World", not only String s = String("Hello") + "World", or something to that effect. Is this correct?
No, in the first example both the left and right side are primitive types and so no code you write can ever affect that operation.

With a member operator:
1
2
3
auto s1 = std::string("hello") + std::string(" world"); //no casts
auto s2 = std::string("hello") + " world"; //implicit cast of second argument
auto s3 = "hello" + std::string(" world"); //would not compile 
With a non-member operator, the last would compile by implicitly casting the first argument.
What do you mean when you say that both the left and right side are primitive types? In this case, I am using String as a custom class, not the standard std::string.
"Hello" is a const char*: a primitive type
"World" is a const char*: a primitive type
You cannot overload operator+ for them.
However, if you have implicit constructor for your string from const char*, you can do stuff like:
1
2
String s = "World";
s = "Hello" + s;
Oh, I see what you mean. However, what do you mean by "implicit constructor"? I thought that meant that the compiler creates one for you. What is the difference between implicit and explicit, then?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct foo
{
    foo(const char*) {std::cout << "foo\n";} //Implicit conversion enabled
};
struct bar
{
    explicit bar(const char*) {std::cout << "bar\n";} //explicit constructor, no implicit conversion
};
void test_foo(foo) {}
void test_bar(bar) {}

int main()
{
    test_foo("Hello"); //Works, foo object will be constructed using const char* constructor
    test_bar("Hello"); //Does not work. You should explicitely create object: test_bar(bar("Hello")); 
}
Ah, I see. Well, I think all my questions have been answered, so thank you both for your help!
Topic archived. No new replies allowed.