Strange compile error when overloading operator != - c++

I have created my own version of operator != so that I can use p != NULL instead of p->b == 0. However, when compiling it (g++ v4.7.3 on Ubuntu 12.04), I get the error:
$ g++ -std=c++11 te2b.cc
te2b.cc:8:41: error: ‘bool operator!=(strDum*, void*)’ must have an argument of class or enumerated type
Here is the code snippet:
#include <vector>
#include <iostream>
struct strDum {
int a;
int b;
};
bool operator!= (strDum *p, void *unused) {
return p->b != 0;
}
int main(void) {
strDum *x = (strDum*) malloc(sizeof(strDum) * 4);
x[0].a = 10; x[0].b = 20;
x[1].a = 100; x[1].b = 200;
x[2].a = 1000; x[2].b = 0;
strDum *y;
for (y=x; y!= NULL; y++) {
printf("%5d %5d\n", y->a, y->b);
}
return 0;
}
Any ideas?
By the way, I prefer p != NULL to p->b == 0 because the structure strDum and the criteria may change frequently (p != NULL may become p->c == 0)
UPDATE1
As the declaration bool operator!= (strDum *p, void *unused) shows, p is only going to be compared with "NULL".

You can not declare an operator which only takes pointers as arguments. From the standard:
13.5.6 Overloaded operators [over.oper]
An operator function shall either be a non-static member function or
be a non-member function that has at least one parameter whose type is
a class, a reference to a class, an enumeration, or a reference to an
enumeration. It is not possible to change the precedence, grouping, or
number of operands of operators. The meaning of the operators
= , (unary) & , and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator
functions that implement these operators. Operator functions are
inherited in the same manner as other base class functions.

You can't declare an operator overloaded function that takes pointers as arguments.
Consider doing this instead:
#include <iostream>
struct strDum {
int a;
int b;
};
template <typename T>
bool operator!= (strDum const& p, T const& number) {
return p.b != number;
}
//may want to include other operators like == as well
int main(void) {
strDum *test = new strDum;
if (*test != 0){
// data member did not equal zero ...
}
return 0;
}

Related

Why in below code return type is class type used for operator overloading?

I have been trying to understand operator overloading and did not get the use of return type as class type in the below program:
When I switch "overload" return type with "int" it works fine.
#include <iostream>
using namespace std;
class overload {
private:
int count;
public:
overload(int i)
: count(i)
{
}
overload operator++(int) //why return type is class type when i can use int
{
return (count++);
}
overload operator++() //why return type is class type when i can use int
{
count = count + 1;
return count;
}
void Display()
{
cout << "Count: " << count<<endl;
}
};
// Driver code
int main()
{
overload i(5);
overload post(5);
overload pre(5);
// this calls "function overload operator ++()" function
pre = ++i;
post = i++;
i.Display();
return 0;
}
The difference between the pre/post increment operators is that one works on the object directly (pre-increment: ++foo), and one needs to take a copy of the object and return that (post increment: foo++). A slightly more verbose way of writing this would be:
// return a new object that represents the old value
overload operator++(int)
{
overload oldValue(count); // take copy
count++; // increment this object
return oldValue;
}
// increment the count, and return a reference to this object
overload& operator++()
{
++count;
return *this;
}
Whilst you could return int (don't do that!), it will only lead to confusion. Effectively it would cause a few issues with code such as:
overload foo = ++someOtherFoo;
Which if you were to return int from ++, would effectively end up calling your constructor function (rather than copy constructor) to construct a new object. i.e.
overload foo = overload(++someOtherFoo);
That constructor might not be available, and so the code would fail.
If you want your object to automatically convert itself to an integer, then the correct way would be to overload the cast operator, e.g.
operator int () const
{
return count;
}
There are no restrictions on the return type of an overloaded operator. Here it can be int as well.
The code you show has the class type as return type to facilitate the other statements in the code as below if ever the constructor of the overload class is marked explicit;
For example with:
explicit overload(int i)
: count(i)
{
}
and
int operator++(int) //return type is int
{
return (count++);
}
int operator++() //return type is int
{
count = count + 1;
return count;
}
The following will fail to compile:
pre = ++i; //will not work
post = i++; //will not work
This is because the implicit copy assignment operator will no longer be viable for conversion from int to const overload.
See Demo
Note that the Canonical implementations of the prefix and postfix increment/decrement operators return overload& and overload respectively.
Although canonical form of pre-increment/pre-decrement returns a reference, as with any operator overload, the return type is user-defined; for example the overloads of these operators for std::atomic return by value

Use class with operator []

i am trying to implement a "Integer" class with expect that it will work like a build-in type int. But i am having a problem: i can't use this class in operator [] like int See my code below:
#include <iostream>
using namespace std;
class Integer
{
private:
int Value;
public:
Integer(int x = 0)
{
Value = x;
}
void SetValue(int x)
{
Value = x;
}
int GetValue()
{
return Value;
}
Integer& operator [] (Integer X);
};
Integer& Integer::operator [] (Integer X)
{
// Code
}
int main()
{
Integer X[10];
Integer I(5);
int i = 5;
for(int i=0; i<10; ++i)
X[i].SetValue(i+1);
cout << X[i].GetValue() << endl; // It still work
cout << X[I].GetValue() << endl; // Doesn't work
return 0;
}
What is a way (exclude cast operator) to make operator [] understand my Integer type like it does with int?
You are thinking about this the wrong way around. You don't need to overload the [] operator on your own class, you actually need your class to be convertable to int, which can be done by overloading the cast operator.
class Integer
{
public:
operator int () const { return Value; }
};
There's a bit of confusion here. The declaration of an array of type T takes the form
T t[n];
where n is a compile time evaluable constant expression for the array size.
This does not invoke any [] operator defined within T, and neither does a subsequent access of an element via the expression t[i] for an integral type i.
If, in your case, you want X[I] to be compilable then you need to provide an operator that allows I to be treated as an array index (more formally the language requires a primitive integral type). A cast operator to int is the obvious choice, with
operator int() const
{
return Value;
}
being the implementation.
You'll need to add a type cast operator to your class. This allows your class to be converted to a compatible type. See here for more information: http://www.cplusplus.com/doc/tutorial/typecasting/
This function should do the trick for your class.
operator int() const { return GetValue(); }
Actually, you don't need to overload the [] operator.
You just need to make sure that you can convert your Integer into an int with int int operator.
Something like this would work better.
operator int() const
{ return GetValue(); }
Then you should also be carefull with your prints.
X[i].GetValue() is wrong since i = 10 in your exemple. This will result in an execution error.
X[I].GetValue() is wrong in your exemple because de conversion between your class and an int is not possible without I.getValue(). I am surprise this doesn't result in a compilation error but overloading the int operator will result this issue tho.

Shouldn't char* implicitly converted to std::string?

Here is my code:
#include <iostream>
using namespace std;
struct ST {};
bool operator==(const struct ST *s1, const string &s2) {
return true;
}
int main() {
struct ST *st = new ST();
const char *p = "abc";
if (st == p) {
return 0;
}
return 1;
}
I get compile error:
prog.cpp:14:12: error: comparison between distinct pointer types ‘ST*’ and ‘const char*’ lacks a cast [-fpermissive]
if (st == p) {
^
I wonder why the implicit conversion from char* to string does not work here?
UPDATE
Anton's answer makes sense, I updated the code:
#include <string>
using namespace std;
struct ST {};
bool operator==(const struct ST s1, const string &s2) {
return true;
}
int main() {
struct ST st;
const char *p = "abc";
if (st == p) {
return 0;
}
return 1;
}
Now it compiles.
§13.3.1.2 Operators in expressions [over.match.oper] states:
If no operand of an operator in an expression has a type that is a class or an enumeration, the operator is assumed to be a built-in operator and interpreted according to Clause 5.
This is exactly your case: operator=='s arguments are pointers, so it's considered to be built-in and compiler doesn't look for possible overloads.
Absolutely not.
First of all, you are trying to use a pointer in place of a reference. Any similarity between a pointer and a reference is a implementation detail. Remember the motto: "Implementation Is Irrelevant!"
Next, and more directly to your question, a std::string and a char* are quite different, even if they are used to represent the same things. Conversion between them was deliberately made difficult to prevent using them interchangably.

how does operator overload resolution work based on return type in the following code of c++

I know that there is no legal overload based on return type in C++; i.e.
you cannot do something like:
int operator ++ getOwner();
char operator ++ getOwner();
However, I stumbled upon the following:
https://stackoverflow.com/a/9569120/1376317
class Proxy
{
My const* myOwner;
public:
Proxy( My const* owner ) : myOwner( owner ) {}
operator int() const
{
return myOwner->getInt();
}
operator char() const
{
return myOwner->getChar();
}
};
My question is how does operator overload work in this configuration. How do you call this in your main.cpp to get this kind of overloading. How does the compiler deduce , how to call the right overload?
My question is how does operator overload work in this configuration.
These operators provide implicit conversions. That means that this class can be used in many contexts where an int or char is expected, and will use these operators to provide the expected value.
How do you call this in your main.cpp to get this kind of overloading.
Here are a few examples of implicit conversions:
Proxy p = whatever();
int i = p; // convert to int
char c = p; // convert to char
long l = p; // ERROR: ambiguous
void f(int);
f(p); // convert to int
void g(int);
void g(char);
g(p); // ERROR: ambiguous
You can also request explicit conversions using the usual cast notations:
long l = static_cast<int>(p); // convert to int, then to long
g((char)p); // convert to char
How does the compiler deduce , how to call the right overload?
Whenever there's a type mismatch, the compiler looks for a conversion sequence. The rules are quite complicated, but basically the sequence can include at most one user-defined conversion (using either an operator like this, or a converting construction), as well as standard conversions such as int to long.
This is sometimes called the Return Type Resolver idiom or "overload on return type". The conversion operator to call is selected thanks to the context of use where an implicit conversion is needed (for example based on the type of an object to initialize or assign to). For example:
#include <stdio.h>
class RtR {
public:
operator int() const
{
puts("operator int()");
return 42;
}
operator double() const
{
puts("operator double()");
return 3.14;
}
};
void f(int) {}
int main()
{
RtR x;
int i = x; // or int i = RtR();
double d = x;
f(x);
}
output:
operator int()
operator double()
operator int()
See it live.
In 13.1 Overloadable declarations:
Function declarations that differ only in the return type cannot be
overloaded. [ Note: ... It does not apply to sets of functions
fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g.,
for operator functions) ... ]
Hence this is valid:
struct X {
// Conversion function:
operator int () { return 1; }
operator double () { return 2; }
};
In addition (not relating directly to the question):
struct Y
{
// Operator (Function call):
int operator () (int) { return 1; }
double operator () (double) { return 2; }
// Operator (Subscripting):
int operator [] (int) { return 1; }
double operator [] (double) { return 2; }
// Operator (Shift):
int operator << (int) { return 1; }
double operator << (double) { return 2; }
// and more ...
};
The above code is for operator type conversions and provide an implicit way to cast the Proxy type to int and char.
The compiler "knows" based on the context of the conversion calls, for instance:
Proxy p;
// p_int will be set equal to p.my_owner->getInt()
int p_int = p;
// p_char will be set equal to p.my_owner->getChar()
char p_char = p;
The fact that it's a proxy is irrelevant; the same thing works for any class. Those are conversion operators, and the compiler does select the right version based on how it's used in the calling code.
struct S {
operator int() const { return 1; }
operator double() const { return 2.0; }
};
int main() {
S s;
int i = s;
double d = s;
std::cout << i << ' ' << d << '\n';
return 0;
}

Pointer Wrapper: dereference operator

I'm pretty new to C++ and as an exercise (and perhaps eventually .Net utility) I'm doing a pointer wrapper (actually in C++/CLI, but this applies to C++ as well). This pointer wrapper (called Apont) currently behaves just like a pointer would, as the test below can show, if lines marked 1. and 2. are commented out:
int main(array<System::String ^> ^args)
{
double ia = 10; double ip = 10;
double *p = &ip; // pointer analogy
Apont<double> ^a =
gcnew Apont<double>(ia); // equivalent to what's below, without errors
a = ~ia;/* 1. IntelliSense: expression must have integral or unscoped enum type
error C2440: '=' : cannot convert from 'double' to 'Utilidades::ComNativos::Apont<T> ^'
error C2171: '~' : illegal on operands of type 'double'*/
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
ia = 20; ip = 20;
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
*p = 30; // pointer analogy
a->Valor = 30; // does exacly what's below, without errors
!a = 30;/* 2. IntelliSense: expression must be a modifiable lvalue
error C2106: '=' : left operand must be l-value */
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
//a->Dispose();
Console::ReadKey();
p = nullptr;
return 0;
}
There are two things I don't like here, marked with 1. and 2. in the code comments, before the lines with errors. The operator~ (see 1.) is defined outside Apont, below:
template<typename T> static Apont<T>^% operator ~(T& valor)
{
return gcnew Apont<T>(valor);
}
I think this one has to be defined outside Apont, but I'm not sure. I cannot understand very well the errors it produces (these are, of course, in the use, not in the definition).
To set the value to which the instance of Apont refers I must use a property (the line marked 2. doesn't work, with errors in the setting usage only), Apont::Valor, which is the equivalent to use *p. What I'd like to do is as I use *p to get or set the value it points to, use !a with the same effect on Apont. Here's Apont::operator!()'s current definition:
T operator !()
{
return Valor;
}
As you can see in 2. (comment in the code, before the respective errors), it doesn't work for setting a value. Maybe I should return a reference? Make another operator with the same name, perhaps outside the class? I tried several options, however, I got similar errors, and came out more confused.
The question is: how can I make an operator that behaves like & (in this case, ~) and one that behaves like * (in this case, !, for dereference, but that behaves like Apont::Valor, whose old definition you can see below)?
property T Valor
{
T get()
{
if (pointer != nullptr)
return *pointer;
else if (eliminado && ErroSeEliminado) // means "disposed && ErrorIfDisposed"
throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
else if (ErroSeNulo) // means "ErrorIfNull"
throw gcnew NullReferenceException();
else
return 0;
// don't worry, this is not default behavior, it is returned only if you want to ignore all errors and if the pointer is null
}
void set(T valor)
{
*pointer = valor;
}
}
Let me recap in a new answer for clarity.
Solving the ! operator is easy, as I said in my previous answer, just add a reference.
So for the operator ~, the goal was to have it behave like the & operator and call the constructor of the pointer wrapper class.
I don't think that is possible. It is certainly possible for user defined objects, but I don't think it is possible to overload unary operators for builtin types. So there are three solutions depending on what you prefer:
The first one does exactly what you want, but will break for primitive types:
#include <iostream>
template<typename T>
struct A {
T* payload;
A()
: payload(NULL){}
A(T *ptr)
: payload(ptr) {}
T& operator !(){
return *payload;
}
};
// this will not work for primary types
template<typename T>
A<T> operator ~(T &b){
return A<T>(&b);
}
struct B{
int test;
};
int main(){
B b; b.test = 4;
A<B> a;
a = ~b; // I think this is what you want
std::cerr << (!a).test << std::endl;
// this does not work
//int i = 4;
//A<int> a;
//a = ~i;
}
Second solution: use a compound assignment operator. Pros are the side effects are minimal, cons is this is not very intuitive and might break the nice design you had in mind.
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
};
template<typename T>
A<T>& operator &=(A<T> &a, T& b){ // should be friend of the above
a.payload = &b;
return a;
}
int main(){
int i = 3;
A<int> a;
a &= i;
std::cerr << !a << std::endl;
}
Third solution: overload the basic assignment operator. This is more intuitive to write but has a lot of side effects:
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
A<T>& operator = (T & b) {
payload = &b;
return *this;
}
};
int main(){
int i = 3;
A<int> a;
a = i;
std::cerr << !a << std::endl;
}
Someone might have a solution to hijack the operators for primitive types, but i can't think of any simple solution.
If i understood your code correctly, you want the operator ~ to return a copy of the pointer wrapper and the operator ! to act as dereference?
In this case, you can define the unary operator ~ inside the Apont class which calls a copy constructor. And the operator ! has to return a reference indeed if you want to asign a value.
I think the following c++ code defines what you want to do (I renamed Apont to A):
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr)
:payload(ptr) {}
A(const A&other)
:payload(other.payload) {}
T& operator !(){
return *payload;
}
T* operator ~(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
PRINT(i);
A<int> a(&i);
!a = 1;
PRINT(i);
A<int> b = ~a;
!b = 2;
PRINT(i);
}
The output of the code above is:
i = 0
i = 1
i = 2
According to your comments, you said you wanted the operator ! to behave exactly like the wrapped pointer. You can do so, but then the syntax changes and you need to dereference it to assign a new value (because it is a pointer...). ie something like:
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr): payload(ptr) {}
// this now behaves like accessing the wrapped pointer directly
T*& operator !(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
int j = 999;
PRINT(i);
A<int> a(&i);
*(!a) = 1; // note the change of syntax here
PRINT(*!a); // and here
!a = &j; // but now you can change the wrapped pointer through the operator
PRINT(*!a);
}