error: use of overloaded operator '*' is ambiguous - c++

When I try to compile this source in c++:
void ParticleSystem::setState(std::vector<Vec2f>& statesVector)
{
std::vector<Vec2f> pState(2);
for (int i = 0; i < 2*np; i += 2) {
pState[0] = *statesVector[i];
pState[1] = *(statesVector[i+1]);
(*particles[i/2]).setState(pState);
}
}
I get the following error:
ParticleSystem.cpp:110:15: error: use of overloaded operator '*' is ambiguous (operand type
'value_type' (aka 'gfx::TVec2<float>'))
pState[0] = *statesVector[i];
^~~~~~~~~~~~~~~~
ParticleSystem.cpp:110:15: note: built-in candidate operator*(float *)
ParticleSystem.cpp:110:15: note: built-in candidate operator*(const float *)
ParticleSystem.cpp:111:15: error: use of overloaded operator '*' is ambiguous (operand type
'value_type' (aka 'gfx::TVec2<float>'))
pState[1] = *(statesVector[i+1]);
I have look for the error already in the forums and followed some steps but i never get to make it work. Moreover, I've also tried to understand the explanation in the notes of the error, but I cannot.
I really hope someone can help me.
Finally, if someone rates this question negatively, at least explain why, please.

The problem is that you didn't understand the syntax that comes with references. While you do declare a reference with &, you use it as you would use the actual variable and not like a pointer, which means you can't use the operator * on it (unless it's a reference on a pointer type). Using the * operator produces the same effects as if you were to use it on a regular variable.
You can fix your problem by removing the * in your code like this:
pState[0] = statesVector[i];
pState[1] = statesVector[i+1];
particles[i/2].setState(pState);
Your code could compile as is if you defined operator* in the Vec2f class and made it return a Vec2f. However, this make little sense in a semantics point of view (a dereferenced value should not give something of the same type) so this is not the way to fix your problem.

Related

Overriding operators/begin/end of a custom Array class

For an exercise we have to implement an array with custom bounds in various different languages, and one of them happens to be c++. Unfortunately i have never had to deal with c++ and am now struggling to get it done. I believe i have the right "core" of the header finished. The idea is that the user specifies bounds in a template and the class fakes this with help of an inner array. We were specifically told to overwrite the [] operator and implement begin() and end() functions. I am currently stuck at the visual studio debugger saying the following:
Error C2228 left of '.end' must have class/struct/union
The gcc compiler is saying:
In file included from Aufgabe1.test.cpp:2:
array.h: In instantiation of 'typename std::__cxx11::list<T>::iterator Array<T, L, H>::begin() [with T = int; int L = -2; int H = 1; typename std::__cxx11::list<T>::iterator = std::_List_iterator<int>]':
Aufgabe1.test.cpp:16:15: required from here
array.h:29:25: error: request for member 'begin' in '((Array<int, -2, 1>*)this)->Array<int, -2, 1>::innerArray', which is of non-class type 'int [4]'
return innerArray.begin;
~~~~~~~~~~~^~~~~
array.h: In instantiation of 'typename std::__cxx11::list<T>::iterator Array<T, L, H>::end() [with T = int; int L = -2; int H = 1; typename std::__cxx11::list<T>::iterator = std::_List_iterator<int>]':
Aufgabe1.test.cpp:16:15: required from here
array.h:33:25: error: request for member 'end' in '((Array<int, -2, 1>*)this)->Array<int, -2, 1>::innerArray', which is of non-class type 'int [4]'
return innerArray.end;
~~~~~~~~~~~^~~
Simply put i have no way of continuing from here since searching for these errors bring no clarification for someone who worked primarily with java so far. How can i solve thse issues and is my implementation of this Array otherwise correct ?
EDIT:
Had to remove the code
The first error message you mention explains the problem fairly well:
Error C2228 left of '.end' must have class/struct/union
The second group of messages tells you where this occurs, specifically when you try to use innerArray.end. The thing to the left of ".end" is innerArray, which is not declared as a class, struct, or union. (It's an array of T.)
So this comes down to the fact that (C-style) arrays do not have member functions. If you need an "end" function, maybe you should look into std::array, which wraps C-style arrays in a class. (If the requirement is to overwrite certain functions instead of implement them, this is the "array" your instructor likely had in mind.)

How to use decltype with member functions

I'm trying to use decltype on member functions in Visual Studio 2012. I've stumbled upon a peculiarity and I'm wondering if this is intention or if it is a compiler bug. Consider (just a code snippet without meaning to show my point):
struct Test { int f() {return 0;} } T;
std::integral_constant<decltype(T.f()), 5>;
std::integral_constant<decltype(&Test::f), 5>; // error C2440
While the second line compiles, the third gives an error C2440: 'specialization' : cannot convert from 'int' to 'int (__thiscall Test::*)(void)'
How come decltype on an instanciated call to a function yields its return type (this is what I am expecting), however trying to do the same without any member involved does yield a member function pointer? If this is the intended behavior, what is the reasoning behind it? How would I denote that I'm requesting the return type of a member function, without actually having an instance at hand? Of course I could do it the dirty way:
std::integral_constant<decltype(((Test*)nullptr)->f()), 5>;
But unquestionable this is pretty, pretty ugly and there should be a clean, straightforward C++ way to express this.
&Test::f does not call the member function Test::f. Instead, it takes the address of the member function and results in a pointer to member function, which is of type int (Test::*)().
In order to do what you want, you should use std::declval. The correct syntax is
std::integral_constant<decltype(std::declval<Test>().f()), 5>

Overloading operator+ with pointers

I'm working on a project on polymorphism in C++ and I have lots of pointers. I need to overload the operator +, so that I can write the following expression naturally:
c=a+b;
with a,b and c being declared as:
A *a,*b,*c;
The basic overloading definitions I know are
A &operator+(const A& a)
A &operator=(const A& a)
but I get the following errors:
invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A* const'
invalid operands of types 'A*' and 'A*' to binary 'operator+'
How should I write the overloaded operator so that I can call it naturally?
I know that my following suggestion is probably not what you want, but for the sake of completeness I tried to find a solution with a template wrapper class around pointers which would permit overloading operator+. I wondered what exactly the combination of lookup rules, template arguments and type conversion could achieve. It turns out that the "natural" use of operator+ seems impossible, but an explicit call works. Here is my code:
/** A wrapper class around arbitrary pointer types */
template<class TPtr> class MyPtrT
{
public:
TPtr ptr;
MyPtrT(const TPtr p = 0) :ptr(p)
{}
};
/** A plus operator on all MyPtrTs */
template<class T>
const MyPtrT<T>&
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
{
return l;
}
MyPtrT<int *> mp1, mp2, mp3;
int *ip;
Ok, what works with these declarations?
// This works (template type explicit) ...
mp3 = operator+<int *>(ip, ip);
// ... and this works (of course,
// arguments match template declaration) ...
mp3 = mp1 + mp2;
And what doesn't (with gcc 4.8.3)?
mp3 = mp1 + ip;
The error is:
smartpointplus.cpp:33:12: error: no match for ‘operator+’ (operand types are ‘MyPtrT<int*>’ and ‘int*’)
mp3 = mp1 + ip;
^
smartpointplus.cpp:33:12: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:33:14: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
I'm not quite sure why the compiler doesn't construct a MyPtrT from the int* argument. It does see the proper function. Perhaps something is wrong with my ctor?
mp3 = operator+(ip, ip);
The error message is similar. The template function is considered but the compiler cannot convert the arguments.
smartpointplus.cpp:36:24: error: no matching function for call to ‘operator+(int*&, int*&)’
mp3 = operator+(ip, ip);
^
smartpointplus.cpp:36:24: note: candidate is:
smartpointplus.cpp:13:1: note: template<class T> const MyPtrT<T>& operator+(const MyPtrT<T>&, const MyPtrT<T>&)
operator+(const MyPtrT<T> &l, const MyPtrT<T> &r)
^
smartpointplus.cpp:13:1: note: template argument deduction/substitution failed:
smartpointplus.cpp:36:24: note: mismatched types ‘const MyPtrT<T>’ and ‘int*’
mp3 = operator+(ip, ip);
It's a bit sad that operator+(ip, ip) (automatically trying to deduce the template type) doesn't work. That limits usability ;-). One would have to templatize all functions using that operator in order to avoid providing the template type explicitly for every call. The infix notation below, by contrast, doesn't even consider the template operator:
mp3 = ip + ip;
The error message is short:
smartpointplus.cpp:38:13: error: invalid operands of types ‘int*’ and ‘int*’ to binary ‘operator+’
mp3 = ip + ip;
I always thought that infix and function style notation of operator calls are just, well, notational differences, but apparently they also change the lookup rules.
tl;dr: What the OP wanted (an infix plus operation with pointer arguments) doesn't work even with a template wrapping class, afaict.
The assignment operator is a special member method (see http://en.cppreference.com/w/cpp/language/operators and http://en.cppreference.com/w/cpp/language/as_operator) and C++ dont allow operator override over pointers after his first standard (before, some implementations allow to do that).

Overloading operator= does not work

I want to overload the operator = and I have the following operator-function
int IntegerClass::operator=(IntegerClass integer) {
return integer.number;
}
This should be correct?
In another class I want to assign the objects private member (int) to another int i.e.
int x = integerClass;
but when I compile I get the following error
error: cannot convert 'std::IntegerClass' to 'int' in initialization
What is wrong with my implementation of operator-overloading and how should the function look like?
Your operator overloads assignment of one IntegerClass to another, but you're trying to assign (actually it's initialization) to a built in int. You need to define an implicit conversion operator.
The code should be something like this (sorry I don't remember the exact syntax)
IntegerClass::operator int() {
return number;
}

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?
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);