I have this class SmallInt that should represent a positive integer value in the range 0-255-inclusive:
struct SmallInt{
explicit SmallInt(int x = 0) : iVal_( !(x < 0 || x > 255) ? x :
throw std::runtime_error(std::to_string(x) + ": value outbounds!")){}
operator int&() { return iVal_; }
int iVal_;
};
int main(){
try{
SmallInt smi(7);
cout << smi << '\n';
cout << smi + 5 << '\n'; // 7 + 5 = 12
cout << smi + 5.88 << '\n'; // 7.0 + 5.88 = 12.88
smi = 33; // error: constructor is explicit
smi.operator int&() = 33;
cout << smi << '\n';
}
catch(std::runtime_error const& re){
std::cout << re.what() << '\n';
}
}
What matters me is: why can I assign to smi explicitly calling operator int&: smi.operator int&() = 33 but not implicitly: smi = 33;?
The first expression (smi = 33;) complains about the constructor SmallInt(int) begin explicit; I know that but I have the conversion operator that returns a modifiable plain lvalue. So in other words why in such an implicit assignment is the constructor preferred to the conversion operator?
[over.match.oper]/4 For the built-in assignment operators, conversions of the left operand are restricted as follows:
...
(4.2) — no user-defined conversions are applied to the left operand to achieve a type match with the left-most
parameter of a built-in candidate.
Thus (int &)smi = 33 interpretation is explicitly prohibited from consideration by the standard.
Related
I tried to raise stack overflow using template like the following :
#include <iostream>
using namespace std;
#define endl '\n'
template <class T>
// void next (T a) cout << a++ << endl; // can't write in a line without {}
void next (T a)
{
if (typeid(a) == typeid((char) 'a') || typeid(a) == typeid((unsigned char) 'a'))
{
cout << typeid(a).name() << " : " << (int) a << " + 1 = " << (int) ++a << " (converted to ASCII value)" << endl;
} else
{
cout << typeid(a).name() << " : " << a << " + 1 = " << ++a << endl;
}
// there will be more alternatives like type_info and so on ……
}
int main()
{
next((char) CHAR_MAX);
next((unsigned char) UCHAR_MAX);
next((short) SHRT_MAX);
next((unsigned short) USHRT_MAX);
next((int) INT_MAX);
next((unsigned int) UINT_MAX);
next((bool) 1); // warning: use of an operand of type 'bool' in 'operator++' is deprecated
return 0;
}
results :
c : 127 + 1 = -128 (converted to ASCII value)
h : 255 + 1 = 0 (converted to ASCII value)
s : 32767 + 1 = -32768
t : 65535 + 1 = 0
i : 2147483647 + 1 = -2147483648
j : 4294967295 + 1 = 0
b : 1 + 1 = 1
This is an advanced code from my previous one using overloading similar functions for each data type(so shame, so it should be secret).
But now I have more question if I can compress the series of next() in main() more. I think it seems to require a container that can have various typed data; for example, {short 1, int 10, long long 100}.
Thank you for your advices & above all, take care of your health.
Indeed, I have no idea what are you asking so I try to answer some related questions and hope this will help :)
To find a maximum value of a type T, use numeric_limits<T>::max() function instead of macros. This way you can only specify the type to call your function:
next<char>();
next<unsigned char>();
next<short>();
...
In the function next I can see how you handle char types in a special way. There is a neat trick that saves you from using if. Expression +a (unary plus) triggers integer promotion and thus will yield you at least type int, which is properly printable as a number. So you can rewrite next like this:
template <class T>
void next()
{
T a = std::numeric_limits<T>::max();
T b = a + 1;
std::cout << typeid(T).name() << " : " << +a << " + 1 = " << +b << std::endl;
}
Answering your original question, now when you got rid of macros in the calls of next you can "iterate" on the types to call it with. In c++ if you need a "collection of types" T1, T2, T3, you usually use std::tuple<T1, T2, T3>. However, in this particular case where you don't have to store this "collection" anywhere, it is actually easier to go with variadic templates and fold expressions:
template<class... Ts>
void print() {
(next<Ts>(), ...);
}
int main()
{
print<char, unsigned char, short, int>();
}
Note how expression (next<Ts>(), ...); expands into (next<char>(), next<unsigned char>(), next<short>(), next<int>());. This is a number of calls separated by operator comma.
As a final point, using ++a or a+1 to find a "next" number is incorrect, since overflowing signed integer types is undefined behavior. You won't necessarily get expected results.
I know there's plenty of questions on this already, so please bear with me on this one.
So I found this question, and I had a doubt about a modification of this.
class Blah {
public:
Blah();
Blah(int x, int y);
int x;
int y;
Blah operator =(Blah rhs);
};
Blah::Blah() {}
Blah::Blah(int xp, int yp) {
x = xp;
y = yp;
}
Blah Blah::operator =(Blah rhs) {
x = rhs.x;
y = rhs.y;
return *this;
}
int main() {
Blah b1(2, 3);
Blah b2(4, 1);
Blah b3(8, 9);
Blah b4(7, 5);
b3 = b4 = b2 = b1;
cout << b3.x << ", " << b3.y << endl;
cout << b4.x << ", " << b4.y << endl;
cout << b2.x << ", " << b2.y << endl;
cout << b1.x << ", " << b1.y << endl;
return 0;
}
So I haven't used return by reference here, while overloading the = operator, and I still get the expected output.
Why should I return by reference? The only difference I see is that copy constructor is called while returning by value but no copy constructor is called while returning by reference.
Could someone please dumb things down for me and explain the concept/idea behind returning by reference? It was taught in my class around almost a year ago, and I still don't understand it.
There is no strict right and wrong here. You can do weird things with operator overloads and sometimes it is appropriate. However, there is rarely a good reason to return a new instance from operator=.
The return value is to enable chaining. Your test for chaining is incomplete. Your line:
b3 = b4 = b2 = b1;
is the same as
b3 = (b4 = (b2 = b1));
And you see expected output for this case. However, chaining like this
(b3 = b4) = b1;
is expected to first assign b4 to b3 then assign b1 to b3. Or you might want to call a method on the returned reference:
(b3 = b4).foo();
As you return a copy, the second assignment will be to a temporary and the member function foo will be called on a temporary, not on b3 as expected. To see this in action consider the output of this
int main() {
Blah b1(2, 3);
Blah b2(4, 1);
Blah b3(8, 9);
Blah b4(7, 5);
(b3 = b4) = b1;
cout << b3.x << ", " << b3.y << endl;
cout << b1.x << ", " << b1.y << endl;
return 0;
}
when returning a copy:
7, 5
2, 3
and when returning a reference:
2, 3
2, 3
The much simpler reason is that you do not want to return a copy when there is no need to make a copy.
Why return by reference while overloading = operator?
Because:
Copying is sometimes expensive, in which case it is good to avoid.
It is conventional. That is also how the built in assignment operators of fundamental types, compiler generated assignment operators of classes, and all the assignment operators of standard types (as far as I know) work.
Given that the special member functions that you've defined don't do anything special, I recommend following class definition instead:
struct Blah {
int x;
int y;
};
Why does this giving compilation problem at bold line?
#include<iostream>
static int i = 10;
int main() {
**(i) ? (std::cout << "First i = " << i << std::endl) : ( i = 10);**
std::cout << "Second i = " << i << std::endl;
}
Compilation message:
test.c:8: error: invalid conversion from ‘void*’ to ‘int’
Your usage of the ternary operator is a bit weird: based on the value of i, you either print something to std::cout or assign a new value to it. Those actions don't share a connection through the return value of an expression, so don't do it like this. When using the ternary operator, it's best to stay closer to its intended purpose: a short notation for two possible expressions with a dispatch based on a simple predicate. Example:
const int n = i == 0 ? 42 : 43;
Your code should look like this:
if (i == 0)
i = 10;
else
std::cout << "First i = " << i << "\n";
The reason the original snippet did not compile is that there is no common return type of the ternary operator. "Common" means that both expressions can be converted to the return type. E.g., in const int n = i == 0 ? 42 : 43; the return type is int.
The problem comes from the fact that the return values of the expressions in your conditional operator (ternary operator) (std::ofstream in the case of the std::cout ..., and int for i = 10) are incompatible and therefore the conditional operator is ill-formed. Please check the rules for return type of the conditional operator.
In this case, just use a normal conditional:
if (i)
std::cout << "First i = " << i << std::endl;
else
i = 10;
Is there anything wrong with writing a reference declaration and assignment in one statement. I have tried it using gcc and it seems to work.
int x = 10;
cout << "x = " << x << "\n";
int &y = x = 11;
cout << "x = " << x << "\n";
cout << "y = " << y << "\n";
gives me the expected output
x = 10
x = 11
y = 11
Is this expected to work on most compilers or will there be a portability issue?
In C++, there is an assignment operator, which can be used (at least in
principle) in any expression. Note that in:
int& y = x = 11;
The first = is not an operator; it is part of the syntax of the data
definition. What follows this = is an expression, which must result
in an lvalue of type int. Since x is an int, x = 11 has type
int. And the result of the built-in assignment operator is an lvalue,
referring to the object which was the target of the assignment, so
you've met the necessary conditions.
Of course, that doesn't mean that it's good code.
I use the stream operator << and the bit shifting operator << in one line.
I am a bit confused, why does code A) not produce the same output than code B)?
A)
int i = 4;
std::cout << i << " " << (i << 1) << std::endl; //4 8
B)
myint m = 4;
std::cout << m << " " << (m << 1) << std::endl; //8 8
class myint:
class myint {
int i;
public:
myint(int ii) {
i = ii;
}
inline myint operator <<(int n){
i = i << n;
return *this;
}
inline operator int(){
return i;
}
};
thanks in advance
Oops
Your second example is undefined behavior.
You have defined the << operator on your myint class as if it were actually <<=. When you execute i << 1, the value in i is not modified, but when you execute m << 1, the value in m is modified.
In C++, it is undefined behavior to both read and write (or write more than once) to a variable without an intervening sequence point, which function calls and operators are not, with respect to their arguments. It is nondeterministic whether the code
std::cout << m << " " << (m << 1) << std::endl;
will output the first m before or after m is updated by m << 1. In fact, your code may do something totally bizarre, or crash. Undefined behavior can lead to literally anything, so avoid it.
One of the proper ways to define the << operator for myint is:
myint operator<< (int n) const
{
return myint(this->i << n);
}
(the this-> is not strictly necessary, just my style when I overload operators)
Because int << X returns a new int. myint << X modifies the current myint. Your myint << operator should be fixed to do the former.
The reason you're getting 8 for the first is that apparently m << 1 is called first in your implementation. The implementation is free to do them in any order.
Your << operator is in fact a <<= operator. If you replace the line with
std::cout << i << " " << (i <<= 1) << std::endl; //8 8
you should get 8 8.
since m is a myInt your second example could be rewritten as:
std::cout << m << " " << (m.operator<<( 1)) << std::endl;
The order of evaluation for the subexpressions m and (m.operator<<( 1)) is unspecified, so there's no saying which "m" you'll get for the 1'st expression that m is used in (which is a simple m expression). So you might get a result of "4 8" or you might get "8 8".
Note that the statement doesn't result in undefined behavior because there are sequence points (at least one function call) between when m is modified and when it's 'read'. But the order of evaluation of the subexpressions is unspecified, so while the compiler has to produce a result (it can't crash - at least not legitimately), there's no saying which of the two possible results it should produce.
So the statement is about as useful as one that has undefined behavior, which is to say it's not very useful.
Well (m << 1) is evaluated before m and therefore m holds 8 already, as in your operator<< you overwrite your own value.
This is wrong behaviour on your side, the operator<< should be const and not change your object.
Because the << operator of myint modifies its lhs. So after evaluating m << 1, m will actually have the value 8 (while i << 1 only returns 8, but does not make i equal to 8). Since it is not specified whether m<<1 executes before cout << m (because it's not specified in which order the arguments of a function or operator are evaluated), it is not specified whether the output will be 8 8 or 4 8.
The C++ language does not define the order of evaluation of operators. It only defines their associativity.
Since your results depend on when the operator<< function is evaluated within the expression, the results are undefined.
Algebraic operator $ functions should always be const and return a new object:
inline myint operator <<(int n) const { // ensure that "this" doesn't change
return i << n; // implicit conversion: call myint::myint(int)
}