Why cant i use two ptrs in operator overload? - c++

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.

Related

Implicit conversion free function [duplicate]

To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...

Why is it called operator overloading?

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.

Problems with the conversion operator and function lookup

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. [...]

Difference between `cout << x` and `cout.operator<<(x)` and `operator(std::cout, x)`?

This is related to the difference-between-cout-x-and-cout-operator-x question, but still a little different...
#include <iostream>
int main(){
std::cout << "hello" << std::endl;
std::cout.operator<<("hello2");
std::cout.operator<<(std::endl);
operator<<(std::cout, "hello3");
// operator<<(std::cout, std::endl);
return 0;
}
Q1: Why does std::cout.operator<<("hello2"); work?
From other answers on SO I would expect the compiler to complain since operator<< is meant to be a free function and not a member of cout. On my system, however, it prints "0x10d54df31". And, stranger yet, the following line correctly correctly executes std::endl.
Q2: Why does operator<<(std::cout, std::endl); not work?
I know that std::endl is a function, but it seems strange (to me) that the hello3 output works whilst the `std::endl' doesn't. Instead the compiler throws an error:
main.cpp:10:4: error: no matching function for call to 'operator<<'
operator<<(std::cout, std::endl);
Q3: How can the first std::cout << "hello1" << std::endl; be written in operator<<(...) form?
If the first two questions have been answered, then this has probably already covered. It's the point of this learning exercise, so seems sensible to ask it explicitly.
Operators can be implemented in different ways, in particular an operator<< for which the left hand side is your type can be implemented as either a free function or as a member function of that left hand side type.
While you must implement ostream& operator<<(ostream&, MyType const&) as a free function (since MyType is not the left hand side), the library implementation can choose* to implement operator<< for some fundamental types insde the std::ostream type (which is really a particular instantiation of a template, I am trying to ignore the details).
Edit: After checking with the standard this is incorrect:
This is what you are noticing in the code, the overload that takes a const char* is implemented as a member of ostream (basic_ostream<char,char_traits<char>).
The overloads taking manipulators are implemented as member functions (Q2), and there is an implicit conversion from const char* to const void* that will be picked if you use the syntax for explicitly calling a member operator (Q1). For Q3, the answer would be:
operator<<(std::cout, "Hello").operator<<(std::endl);
* The implementation is actually not free to choose, since the standard mandates the signatures.
Some overloads of operator<< are class members, others are not.
In C++03 this created some baffling call scenarios since a reference to non-const (argument of the not-member) can't be bound to an rvalue, but in C++11 at least one such has been fixed by introducing an rvalue reference argument overload.
So, which calls compile or not depends more in general also on the C++ standards version, C++03 or C++11.
There is a bunch of member output operators defined in std::ostream. In retrospect that was probably an error but when IOStreams were first created I think it was actually necessary. These member operators include the overloads taking function pointers which means you'll need to use member notation for those. The operators using C-strings are non-member overloads, i.e., you need to use the non-member function call notation to get the C-string overload. When you call the member operator with a char const* the char const* will be converted to void const* for which there is a member output operator.
Your questions can be broken down to member functions an non-member functions.
Having 13.5.2 Binary operators
A binary operator shall be implemented
either by a non-static member function (9.3) with one parameter or by
a non-member function with two parameters. Thus, for any binary
operator #, x#y can be interpreted as either x.operator#(y) or
operator#(x,y). If both forms of the operator function have been
declared, the rules in 13.3.1.2 determine which, if any,
interpretation is used.
Omitting a quote of 13.3.1.2 the member function (operator) is preferred.
The line 'std::cout << "hello" << std::endl;' involves non member functions. Each 'std::cout.operator' is an explicit member function call.
Q1 is the member operator<<(const void*)
Q2 there is no member taking a function
Q3 It is not possible

Overloading the global type conversion operator

To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...