I'm currently trying to refactor some code which uses a primitive type into something which I can tuck setters and getters into them. I wanted to make the change to the underlying code transparent, and at first I though C++'s operator overloads would help me out there.
Let's suppose I want to make an "augmented int" type, for instance, that can be treated just like a regular int, but allows for further action wherever I assign to it, and just assignment - all other properties of an int, such as adding with +=, should be preserved.
At first I first though that if I encapsulated the int inside some struct, and filled out the operator= overloads, I'd be set, like in the following example:
#include<iostream>
typedef struct PowerInt{
int x;
PowerInt(){
cout << "PowerInt created\n";
x = 0;
}
~PowerInt(){
cout << "PowerInt destroyed\n";
}
void operator=(int other){
cout << "PowerInt received " << other << "\n";
this->x = other;
}
}PowerInt;
int main(){
PowerInt a;
a = 3;
return 0;
}
The code compiles and runs as expected, but as soon as I try making anything else a regular int could do, like cout << a, or a += 2, or even a simple int b = a; assignment the compiler complains about the operators << and += missing.
Fair enough; I then though that, at least for << and "assigment =", I could get by using some sort of "generic rvalue operator", or some kind of method which returns PowerInt.x wherever my a is used as an rvalue, automatically making expressions like int c = (a + 3); and if (a == 3) {} valid.
Problem is, I can't find a way to implement this idiom, and this mostly likely has to do with either my little understanding of how operator overloading works in C++, or some language feature I'm not yet aware of. Is it possible to accomplish what I'm trying here?
If you want your PowerInt to be convertible to a normal int you can create a user-defined conversion operator:
operator int() const
{
return x;
}
Any operator that's not defined for PowerInt will then use the operator defined for a normal int.
P.S The typedef struct isn't necessary in C++.
Related
I've having My with an implicit ctor My(int i), I wish to cast an int into My, so I have:
#include <any>
#include <iostream>
using namespace std;
struct My {
My(int i) { cout << "int ctor\n"; }
};
ostream& operator << (ostream& os, const My& m) {
os << "My object\n";
return os;
}
int main() {
any a = 1;
auto am = My(any_cast<int>(a));
cout << a.type().name() << ": " << any_cast<int>(a) << '\n';
cout << a.type().name() << ": " << any_cast<My>(a) << '\n';
return 0;
}
Upon running, it prints:
int ctor
i: 1
i: terminate called after throwing an instance of 'std::bad_any_cast'
what(): bad any_cast
I expected that any_cast<My>(a) should be able to call My(a) to construct a new object, but actually not.
Did I mis-undertand anything?
This is simply not how std::any_cast works. It is not literally a cast between types like e.g. static_cast is.
You must provide the exact type stored in the std::any object to access its value (via std::any_cast). It is impossible to imply any conversions.
Because the type stored in the std::any is only determined at runtime, the compiler would need to emit code for every possible type that could be stored in it and be convertible to the target type, if implicit conversions were allowed. That is clearly infeasible or impossible.
There are only very few situations where std::any is the right tool for the job. In particular it will not allow you to circumvent the statically-typed nature of C++.
I expected that any_cast(a) should be able to call My(a) to construct a new object, but actually not.
No, any_cast<T>(a) succeeds if and only if T is present in a. It answers the query whether there is T in a. Not whether there is some type implicitly convertible to T. You have to do that after extracting the value yourself.
As for the manual
Throws std::bad_any_cast if the typeid of the requested T does not match that of the contents of operand.
a should contain the exact type My.
I expected that any_cast(a) should be able to call My(a) to construct a new object, but actually not.
It does not call converting constructors.
Could somebody explain what the difference is in this example of operator overloading, Average& operator+=(int num) where you return a reference to Average versus not returning a reference to Average i.e. Average operator+=(int num).
Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
How/why does the non reference version work? Where is the result being copied?
#include <iostream>
#include <cstdint> // for fixed width integers
class Average
{
private:
int32_t m_total = 0; // the sum of all numbers we've seen so far
int8_t m_numbers = 0; // the count of numbers we've seen so far
public:
Average()
{
}
friend std::ostream& operator<<(std::ostream &out, const Average &average)
{
// Our average is the sum of the numbers we've seen divided by the count of the numbers we've seen
// We need to remember to do a floating point division here, not an integer division
out << static_cast<double>(average.m_total) / average.m_numbers;
return out;
}
// Because operator+= modifies its left operand, we'll write it as a member
Average& operator+=(int num)
{
// Increment our total by the new number
m_total += num;
// And increase the count by 1
++m_numbers;
// return *this in case someone wants to chain +='s together
return *this;
}
};
int main()
{
Average avg;
avg += 4;
std::cout << avg << '\n';
return 0;
}
You should return a reference because thats a convention most code in standard library is using, and most programmers do. Most programmers will expect below code:
std::string s;
(s += "a") = "b";
std::cout << s << std::endl;
to print b, or in this example:
int n = 10;
(n += 20) = 100;
std::cout << n << std::endl;
will expect 100 to be printed.
That is why you should return a reference to keep with the convention which allows to modify object which is on the left side of assignment.
Otherwise, if you return by value (a copy) assignment as in above examples will assign to a temporary.
When overriding operators in C++, one can provide them in multiple forms. You can define assignment operators which do not return a reference to the modified object, and they would work as expected. But, we have for each operator what we call a canonical implementation:
Other than the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator+ is expected to add, rather than multiply its arguments, operator= is expected to assign, etc. The related operators are expected to behave similarly (operator+ and operator+= do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d, because the built-in operators allow that.
Commonly overloaded operators have the following typical, canonical forms.
There is a lot to read about those canonical forms, but I'd suggest to start with this really good SO answer on What are the basic rules and idioms for operator overloading?
How/why does the non reference version work?
Because even if the C++ Standard encourages you to use the canonical forms, it doesn't forbid you not to.
Where is the result being copied?
Nowhere, the value is discarded. Implementation will probably optimize them away.
Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
Yes.
How/why does the non reference version work? Where is the result being copied?
The returned value is a temporary object that is passed to std::cout <<.
It's similar to using:
int foo()
{
return 10;
}
std::cout << foo() << std::endl;
The return value of foo is a temporary object that is passed to std::cout <<.
Try to check this similar question.
When you return reference, you are actually passing the actual object. While when you return by value, temporary object is created and then passed to caller.
So if you return without reference this assignment may work as per your code segment above.
Average aa = avg += 4;
But it will fail to compile if you try.
Average *ptr = &(avg += 4);
The above code will work if you return reference though, since we are passing valid scope of object.
I've made this class BigInt, and it it has derived transformation constructors such as
BigInt::BigInt(int l):InfInt(l){}
Yet when I do something like this:
for(i=0;BigInt::pow(2,i+1)<exponent;i++);
The compiler yells at me for:
error: ambiguous overload for ‘operator+’ (operand types are ‘BigInt’ and ‘int’)
I know a simple way to fix this is simply to add (BigInt) in front of everything, like this:
for(i=0;BigInt::pow(2,i+(BigInt)1)<exponent;i++);
But this code looks ugly, somewhat hard to read, and is a pain to type. Is there a way to tell the compiler to do this right away (as the title already says) ? It's not too dramatic if there isn't though.
Oh, and excuse me if this has been already asked, but I have tried to search for a solution on my own on google and here and have found nothing that could help me out. (I was mostly able to find stuff about operator int() and the like, which I already knew about).
You also have an operator int(), don't you? That, plus the constructor that takes an int, produces the ambiguity. The compiler can call BigInt::operator+() by converting the int argument to a BigInt, or it can call the built-in + by converting the BigInt object to an int. Mark the operator int() explicit to get rid of this ambiguity. That will lead to failed conversions in a few situations, which can be resolved by adding a cast. That's the best you can do; there are no conversion precedence rules that can make the compiler see BigInt as the largest integral type.
Not sure what the problem is. Does comparing against this help:
#include <iostream>
struct MyInt
{
MyInt(int i) : m_i(i) {}
MyInt operator+(const MyInt& myint) const
{
return MyInt(m_i+myint.m_i);
}
int m_i;
};
int main()
{
MyInt a(10);
MyInt b(5);
MyInt c1 = a + b;
MyInt c2 = a + 5;
std::cout << c1.m_i << std::endl;
std::cout << c2.m_i << std::endl;
return 0;
}
This is a follow up question from Calling constructor in return statement.
This a operator overload fun in a class.
const Integer operator+(const Integer& IntObject)
{
cout << "Data : " << this->data << endl;
return Integer(this->data + IntObject.data);
}
What is the relevance of const in the return type for such functions?
int main()
{
Integer A(1); //Create 2 object of class Integer
Integer B(2);
const Integer C = A + B; //This will work
Integer D = A + B; //This will also work
fun(A + B); //Will work
}
void fun(Integer F) {}
This is a case temporaries are not created during return step due to NRVO. The object to be returned is directly constructed on the callee's address.
Here's a better example:
struct Foo
{
void gizmo();
Foo const operator+(Foo const & rhs);
};
Now if you have a Foo x; Foo y;, then you cannot say:
(x + y).gizmo(); // error!
The constant return value means you cannot use it for non-constant operations. For primitive types this is not quite so relevant, because there aren't many non-constant operations you can perform on temporary objects, because lots of "interesting" operations (like prefix-++) aren't allowed on temporaries.
That said, with C++11 one should really try and adopt the new idiom of never returning constant values, since non-constant values are now amenable to move optimisations.
Some people used to suggest doing that, to prevent writing nonsense like A + B = C. However, in C++11 it can prevent some optimisations since it makes the return value unmovable. Therefore, you shouldn't do it.
In this case, it also prevents you from writing perfectly valid code like D = A + B + C, but that's just because the author forgot to declare the operator const.
There is no relevance in your code snippet, because you are making a copy of the returned value.
In general, it is difficult to find good reasons to return a const value. I can only see it having an effect in this type of expression, attempting to call a non-const method on a const temporary:
(someObject.someMethodReturningConstValue()).someNonConstMethod(); // error, calls non const method on const temporary
so you should only use it if you want to disallow calling non-const methods on temporaries. On the other hand, it kills move-semantics in C++11 so is discouraged.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Overloading operator ->
Hi,
I've seen that operator->() is chained (re-applied) after it is evaluated, for example:
struct Bar
{
Bar() : m_str("Hello world!") {}
const string* operator->() const { return &m_str; }
string m_str;
};
struct Foo
{
const Bar& operator->() const { return m_bar; }
Bar m_bar;
};
int main()
{
Foo f;
cout << f->c_str() << endl;
return 0;
}
works pretty fine, which requires three operator->() to be evaluated - Foo::operator->(), Bar::operator->() and regular pointer resolution.
But it wont work with pointers in the middle - if Foo::operator->() returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>> for example.
Is it specific to non-overloaded operator->() so it is only applied once and does not cause chaining?
Is it possible to make code below works without using (*ptr2)-> ...?
int main()
{
string s = "Hello world";
auto_ptr<string> ptr1(&s);
auto_ptr<auto_ptr<string> > ptr2(&ptr1);
cout << ptr1->c_str() << endl; // fine
cout << ptr2->c_str() << endl; // breaks compilation
}
Thanks!
C++98 standard §13.5.6/1 "Class member access":
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).
What this means in practice is that when x is a pointer, you don’t get chaining; you then just get the built-in operator-> (i.e. x->m with x a pointer translates to (*x).m).
But when x is an object of class type T, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m can be that (x.operator->()) itself is an object of some class, say class U. Whence the second -> can be resolved as U::operator->, and so on, if the result of that again is a class type object…
Like, in your case, Foo::operator-> produces (a reference to) an object of class Bar, which does define an operator->.
But when operator-> returns a pointer, as e.g. std::auto_ptr<T>::operator-> does, then it's just the built-in operator-> that's used.
In passing, the chaining can be used to practically prevent someone from using delete inappropriately. std::auto_ptr does not do that. And I’ve never seen it done.
But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.
Cheers & hth.
The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr you actually are returned a real pointer and the default operator -> is invoked for regular pointers.
Please see the Overloading operator -> question for more details.
No, it is not possible for it to work. If you could overload operator -> for string * you could make it work. But operator -> already has a definition for all pointer types. So, just like you can't overload + for primitive numeric types, you can't overload operator -> for any pointer type.
And even if you could, how could the compiler know when the recursion should end?