Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is g++ saying 'no match for ‘operator=’ when there clearly is, and Visual Studio can see that there is?

I'm writing an interface library that allows access to variables within tables (up to a theoretically infinite depth) in an object of type regula::State. I'm accomplishing this by overloading operator[] within a class, which then returns another of that same class, and calls operator[] again as needed. For example:

regula::State t;
t["math"]["pi"] = 3.14159;

The above is supposed to place the value 3.14159 within variable pi in table math. Basically, it does this by have t return a proxy object representing math, which returns another proxy object representing pi, to which we actually save the variable. The internals of this aren't really relevant to the question, but here is the function header.

LObject LObject::operator[] (const std::string name);

Basically, in the example above, the program should call t's operator[] with the string "math" and return another object, and then call that object's operator[] with the string "pi", which returns the final object, and then assigns the value to that one using operator=.

template <typename T>
T LObject::operator= (const T& value);

The T returned is just a copy of the value passed.

Now, my code produces NO errors in Visual C++ 2008 and works perfectly. But when I try to compile it on Linux with g++, I get the following error:

../../test/regula-test.cpp:100: error: no match for ‘operator=’ in 
‘L.regula::State::operator[](std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >(((const char*)"Numbers"), ((const std::allocator<char>&)((const 
std::allocator<char>*)(& std::allocator<char>()))))) = Numbers’
../../include/regula.hpp:855: note: candidates are: regula::LObject&
 regula::LObject::operator=(const regula::LObject&)

For some reason, g++ seems to be trying to call operator= on operator[], rather than on the returned object like it is supposed to be.

I can actually fix this error by replacing the return type on operator= with void:

template <typename T>
/*T*/ void LObject::operator= (const T& value);

But this is not preferable, and besides, I have similar errors in several other locations with a similarly overloaded operator==:

../../test/regula-test.cpp:153: error: no match for ‘operator==’ in ‘pi == 
L.regula::State::operator[](std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >(((const char*)"pi"), ((const std::allocator<char>&)((const 
std::allocator<char>*)(& std::allocator<char>())))))’

I don't understand why this error is occurring in g++, or why it is not occurring in Visual C++. Can anyone shed any light on this or recommend any solutions?

like image 511
pdusen Avatar asked Dec 22 '09 17:12

pdusen


1 Answers

Section 5.17 of the ISO standard says

There are several assignment operators, all of which group right-to-left. All require a modifiable lvalue as their left operand, and the type of an assignment expression is that of its left operand. The result of the assignment operation is the value stored in the left operand after the assignment has taken place; the result is an lvalue.

Your operator= returns not only the wrong type, but not even an lvalue. Assuming GCC's error message didn't include any other candidates besides operator=(const regula::LObject&), GCC has simply ignored your overload entirely. The operator= it mentions is the default, automatically generated function.

On second glance, your operator[] also should return a reference. As written, no assignment expressions like your example should work at all.

So, you should have functions

LObject &LObject::operator[] (const std::string name);

and

template <typename T>
LObject &LObject::operator= (const T& value);
like image 129
Potatoswatter Avatar answered Sep 19 '22 03:09

Potatoswatter