I have a class, let's call it Wrapper, that wraps a given type, let's say MyClass.
In reality, Wrapper is a class template, but I think that's not relevant here.
Wrapper exposes the wrapped MyClass by means of a conversion operator (just for reading).
When I create an operator for MyClass as free function (in my example a unary minus operator), this works as expected, I can use the operator also on the Wrapper class.
If I, however, implement the operator as a member function, the compiler complains: error: no match for ‘operator-’.
I thought the free function and the member function are equivalent in this case, why aren't they?
Is there a way to change the Wrapper class that a member operator or MyClass works?
If there isn't, does this suggest that it is in general preferable to implement an operator as free function instead of as member function?
Here's some code to illustrate the problem.
struct MyClass {
// This doesn't work:
void operator-() const {}
};
// It works with this instead of the member operator:
//void operator-(const MyClass&) {}
struct Wrapper {
operator MyClass() const { return MyClass(); }
};
int main() {
-Wrapper();
}
Here's a live example: http://ideone.com/nY6JzR
Question I thought the free function and the member function are equivalent in this case, why aren't they?
Answer
In order for -Wrapper() to work correctly, the compiler has to perform a lookup for operator-. It looks for the name operator- in the default namespace, in the class Wrapper, and the namespace where Wrapper is defined. It doesn't look at other classes and namespaces for the name.
That explains the compiler error when the operator-() is moved to MyClass and why it succeeds when it is defined as a non-member function.
Question Is there a way to change the Wrapper class that a member operator or MyClass works?
Answer There are two ways to resolve this.
Make the operator functions for MyClass non-member functions.
Create operator functions in MyClass as well as Wrapper, with the implementations in Wrapper being simple pass through functions. The good thing about this is that then you don't have to care whether the operator functions in MyClass are member functions or non-member functions.
Question If there isn't, does this suggest that it is in general preferable to implement an operator as free function instead of as member function?
Answer This can be a policy decision based on the choice you make to the previous answer.
I thought the free function and the member function are equivalent in
this case, why aren't they?
Lets see what happens when a conversion operator is used.
Essentially, there is a global operator function, which has a parameter of type MyClass. Now, since Wrapper has a conversion operator, the call operator-( Wrapper() ) will be inspected by overload resolution to find the best match - and overload resolution finds that there is a global operator function with parameter MyClass const& (or similiar). Then it tries to convert the Wrapper prvalue to MyClass const& and sees that there is a user-defined conversion sequence: One that uses the conversion operator to convert the Wrapper-object to a MyClass object, which then can be used to (copy-)initialize the reference.
If the operator function is a member instead, there is a problem: A global function call of the form operator-( Wrapper() ) does obviously not yield any viable functions. But the one that assumes the operator function is a member doesn't yield anything either - because operator- is not a member of Wrapper, therefore Wrapper().operator-() doesn't work and doesn't yield any viable functions either.
Remember: A class with a conversion operator does not inherit the members of the target type. If you wanted that, you should have inherited MyClass.
For a unary operator # with an operand of a type whose cv-unqualified
version is T1 [...] three sets of candidate functions, designated
member candidates, non-member candidates and built-in candidates, are
constructed as follows:
If T1 is a complete class type, the set of member candidates is the
result of the qualified lookup of T1::operator# (13.3.1.1.1);
otherwise, the set of member candidates is empty.
The set of non-member candidates is the result of the unqualified lookup of
operator# in the context of the expression according to the usual
rules for name lookup in unqualified function calls (3.4.2) except
that all member functions are ignored. [...]
Related
If the following class, Foo, is defined. It is said it overloads the unary ampersand (&) operator:
class Foo {
public:
Foo* operator&() { return nullptr; }
};
I think in this case, (reglardless of the fact that you can get the address of such an object by means of std::addressof() and other idiomatic tricks) there is no way to access/choose the original unary ampersand operator that returns the address of the object called on, am I wrong?
By overloading however, I understand that there is a set of functions of which one will be selected at compile-time based on some criteria. But this thinking doesn't seem to match the scenario above.
Why is it then called overloading and not something else like redefining or replacing?
Consider the following code:
int x;
Foo y;
&x; // built-in functionality
&y; // y.operator&();
We have two variables of different types. We apply the same & operator to both of them. For x it uses the built-in address-of operator whereas for y it calls your user-defined function.
That's exactly what you're describing as overloading: There are multiple functions (well, one of them is the built-in functionality, not really a "function") and they're selected based on the type of the operand.
You can't redefine a function or operator in C++, you can add only new use to it, defining new set of arguments. That's why it called overloading instead of redefining.
When you overload operator as a member of class you
1) defined it with first argument supposed to be an instance of that class
2) gave it access to all members of that class.
There are still definitions of operator& with different arguments and you have a non-zero chance to create situation where use of operator would be ambigous.
This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution
This question gives a good answer why to define operator overloads as non-members: Operator overloading : member function vs. non-member function?
If you define your operator overloaded function as member function,
then compiler translates expressions like s1 + s2 into
s1.operator+(s2). That means, the operator overloaded member function
gets invoked on the first operand. That is how member functions work!
But what if the first operand is not a class? There's a major problem
if we want to overload an operator where the first operand is not a
class type, rather say double. So you cannot write like this 10.0 +
s2. However, you can write operator overloaded member function for
expressions like s1 + 10.0.
Now I have a situation where I need to overload operator==. In my case, only (a) objects of (b) the same type will be compared.
Is there a reason to still define operator== as a non-member or should I implement it as a member in that case?
Because operator== has symmetric semantics for its LHS and RHS argument, the recommended approach is to always implement it as a non-member in terms of the public interface of its operands (or if private data is required, to declare it as a friend inside the class).
So
class Bla
{
public:
// complete interface to data required for comparison
auto first();
auto second();
// ... more
private:
// data goes here
};
bool operator==(Bla const& L, Bla const& R)
{
return
std::forward_as_tuple(L.first(), L.second() /*, ... */) ==
std::forward_as_tuple(R.first(), R.second() /*, ... */)
;
}
This way, implicit conversion to Bla are considered for both the L and R arguments (I'm not saying implicit conversions are a good idea, but if you have those, it's better to avoid surprises where they are only considered for the RHS argument).
This is annoying, i can write a function with these parameters/return, but why cant i define an operator to do this?
-edit- i am actually trying to overload << the below is just for reference.
From msdn
// C2803.cpp
// compile with: /c
class A{};
bool operator< (const A *left, const A *right); // C2803
// try the following line instead
// bool operator< (const A& left, const A& right);
gcc error
error: ‘bool operator<(const A*, const A*)’ must have an argument of class or enumerated type
Because every user-defined operator overload needs at least one user-defined type as a parameter. A point isn't a user-defined type.
C++03 standard, §13.5 [over.oper] p6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.
Because you aren't allowed to cheat.
If you could override comparison operators for pointer types, then you would no longer be able to compare those pointers by value (aka: by the actual numerical pointer values). And that's kind of important and occasionally useful.
My real code is actually <<. Why cant i use it for that?
For the same reason: pointers are C++-basic types. They aren't user-defined types. Do you want to be able to not left-shift pointer values anymore? OK, obviously you do, but C++ won't let you.
You can only override operators when C++ does not have existing functionality for operators with those types (with a few exceptions). C++ already has operator< and operator<< for pointers, so you're not allowed to change what they do.
I am currently creating a utility class that will have overloaded operators in it. What are the pros and cons of either making them member or non-member (friend) functions? Or does it matter at all? Maybe there is a best practice for this?
I'd go with "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices": if you can do it as non-member function, do it as non-member function (in the same namespace).
One of the reasons: it works better with implicit type conversion. An Example: You have a complex class with an overloaded operator*. If you want to write 2.0 * aComplexNumber, you need the operator* to be a non-member function.
Another reason: less coupling. Non-member-functions a less closely coupled than member functions. This is almost always a good thing.
Each operator has its own considerations. For example, the << operator (when used for stream output, not bit shifting) gets an ostream as its first parameter, so it can't be a member of your class. If you're implementing the addition operator, you'll probably want to benefit from automatic type conversions on both sides, therefore you'll go with a non-member as well, etc...
As for allowing specialization through inheritance, a common pattern is to implement a non-member operator in terms of a virtual member function (e.g. operator<< calls a virtual function print() on the object being passed).
If you plan on implementing streaming operators (<< and >>) then they will be non-members methods because your object is on the left of the operator.
If you plan on implementing ->, () or [] they are naturally member methods.
For the others (comparison and mathematical) you should check out Boost.Operators, it really helps.
For example, if you want to implement the following operators:
MyClass& MyClass::operator+=(int);
MyClass operator+(const MyClass&, int);
MyClass operator+(int, const MyClass&);
You only have to write:
class MyClass: boost::operator::addable<MyClass,int> // no need for public there
{
public:
MyClass& operator+=(int);
private:
};
The 2 operator+ will be automatically generated as non-members which will let you benefit from automatic conversions. And they will be implemented efficiently in term of operator+= so you write code only once.
For binary operators, one limitation of member functions is that the left object must be of your class type. This can limit using the operator symmetrically.
Consider a simple string class:
class str
{
public:
str(const char *);
str(const str &other);
};
If you implement operator+ as a member function, while str("1") + "2" will compile, "1" + str("2") will not compile.
But if you implement operator+ as a non-member function, then both of those statements will be legal.
If you are implementing op, then most probably you need to implement op=. i.e. if you are overloading + operator, then you should implement +=.
Make sure that you are returning const to an object if you are doing post-increment or overloading + operator.
So, if you overload operator + , then implement it as a non-member operator and use += operator inside it. For eg.
const A operator+(const A& lhs, const A& rhs)
{
A ret(lhs);
ret += rhs;
return ret;
}
There is nothing like best practices but it depends on the operator you are overloading ..
For e.g .
>> and << can't be overloaded as member functions .
Suppose you want to do like this : obj1 = 2 * obj2 then go for non-member function.
For binary operator overloading member function takes only 1 parameter (invoking object is impcliitly passed ) whereas non-member function takes 2 parameters .