Consider this code:
# include <iostream>
using namespace std;
int main()
{
for(int i = 5; i>0;)
{
i--;
cout <<i<<" ";
}
return 0;
}
The output of this code would be 4 3 2 1 0.
Can I change the decrement/increment value?
In detail, this means that the default decrement/increment value is 1. So you either minus 1 or add 1.
Can I change it to minus 0.2 or add 1.3?
If so, is there a way to tell the compiler that I want to change the -- value from 1 to 0.2 and still using the -- operator instead of changing it to -= 0.2?
d-- is shorthand for d -= 1, which is shorthand for d = d - 1.
You should not read this as a mathematical equation, but as "calculate d - 1 and assign the result as the new value of d".
#include <iostream>
int main()
{
float day = 1.2;
for(int i = 0; i < 5; i++)
{
day -= 0.2;
std::cout << day;
}
return 0;
}
(I also removed using namespace std as it is bad practice).
Note the second part of the for loop is a condition that keeps the loop going as long as it is true. In your case, i > 5 is false from the beginning (because 0 < 5) so the loop will never run. I assumed you meant i < 5 instead.
i-- is the post-fix decrement operator. For builtin types it means that i is decremented by one (1). The value of the expression i-- is the value of i before decrementing it.
--i is the pre-fix decrement operator. For builtin types it means that i is decremented by one (1). The value of the expression --i is the value of i after decrementing it.
For the builtin types you cannot change the behaviour of the increment or decrement operators. If you want to have another behaviour, you need to fallback to the operators += and -= where you can add whatever you want. But please note that your code used int and you probably want to change to float or double first before adding or subtracting 0.1 or 0.2.
You can change the behaviour for increment and decrement operators for your own types, though. Here is an exammple
#include <iostream>
struct S {
S& operator++() { // prefix increment "++s"
d += increment_value;
return *this;
}
S& operator--() { // prefix decrement "--s"
d -= decrement_value;
return *this;
}
S operator++(int) { // postfix increment "s++"
S copy{*this};
d += increment_value;
return copy;
}
S operator--(int) { // postfix decrement "s--"
S copy{*this};
d -= decrement_value;
return copy;
}
double d{};
double increment_value{0.2};
double decrement_value{0.1};
friend std::ostream& operator<<(std::ostream& os, const S& s) {
os << s.d;
return os;
}
};
int main(int, char**) {
S s{1};
std::cout << "val=" << s.d << '\n';
std::cout << "prefix++=" << ++s << '\n';
;
std::cout << "val=" << s.d << '\n';
std::cout << "postfix++=" << s++ << '\n';
std::cout << "val=" << s.d << '\n';
std::cout << "prefix--=" << --s << '\n';
std::cout << "val=" << s.d << '\n';
std::cout << "postfix--=" << s-- << '\n';
std::cout << "val=" << s.d << '\n';
}
The output is
val=1
prefix++=1.2
val=1.2
postfix++=1.2
val=1.4
prefix--=1.3
val=1.3
postfix--=1.3
val=1.2
You might notice that I added two operator ++ and two operator--. One of each is getting no parameter, the other is getting an int. As cppreference describes, the int parameter is only a dummy parameter to differentiate between the prefix and the postfix versions of the operators. (*)
As you can also see, the prefix operators are more performant as they don't need the extra copy. So normally please use the prefix versions (compare the CppCoreGuidelines).
But, please ignore the possibility to change the increment and decrement operators. It is counter intuitive and only a source of errors and head aches. Don't do it this way!
(*) This parameter could also be used for even more confusing behaviour, but it should be clear that this is making the idea even worse. So see this just as an example of what is technically possible.
#include <iostream>
struct S {
S operator++(int diff) { // postfix increment "s++", diff defaults to zero (0)
S copy{*this};
d += diff ? diff : increment_value;
return copy;
}
S operator--(int diff) { // postfix decrement "s--", diff defaults to zero (0)
S copy{*this};
d -= diff ? diff : decrement_value;
return copy;
}
double d{};
double increment_value{0.2};
double decrement_value{0.1};
friend std::ostream& operator<<(std::ostream& os, const S& s) {
os << s.d;
return os;
}
};
int main(int, char**) {
S s{1};
std::cout << "val=" << s.d << '\n';
s++;
std::cout << "val=" << s.d << '\n';
s.operator++(2);
std::cout << "val=" << s.d << '\n';
s--;
std::cout << "val=" << s.d << '\n';
s.operator--(2);
std::cout << "val=" << s.d << '\n';
}
results in
val=1
val=1.2
val=3.2
val=3.1
val=1.1
You can change the loop variable both inside the for and the body any way you like. For example:
for (double d = 4; d > 0; d = cos(d) + 1 / d) {
d = sin(d);
std::cout << d << " ";
}
C++ does not have a fixed count loop like other languages for i = 0 to 10 do ... done where the i can not be changed. Do whatever you like.
Note: I change the type to double since you asked about decrementing by 0.2. The type int doesn't allow that.
Can I change the decrement/increment value?
Yes, that is what the third parameter(?) in the for loop does.
#include <iostream>
int main()
{
for(int i = 5; i > 0; i -= 2)
{
std::cout << i << std::endl;
}
return 0;
}
Can I change it to minus 0.2 or add 1.3?
Yes, you'd simply change the first parameter to be a float and the third parameter to decrement/increment by whatever you'd like.
#include <iostream>
int main()
{
for (float i = 5; i > 0; i -= .2)
{
std::cout << i << std::endl;
}
return 0;
}
If I understand correctly what you want to do is to change the behavior of T operator --();.
You can do that with your own type:
struct Foo {
float boat;
auto operator --() noexcept { return boat -= .2f; }
operator float() const noexcept { return boat; }
};
#include <cstdio>
int main() {
for (Foo i{ 5 }; i > 0; --i) {
std::printf("%1.2f, ", static_cast<float> (i));
}
}
Live on Compiler Explorer
Should you ever do that? No, you shouldn't. But now you know how not to do it should the opportunity not come.
Related
Is it possible to perfectly forward *this object inside member functions? If yes, then how can we do it? If no, then why not, and what alternatives do we have to achieve the same effect.
Please see the code snippet below to understand the question better.
class Experiment {
public:
double i, j;
Experiment(double p_i = 0, double p_j = 0) : i(p_i), j(p_j) {}
double sum() { return i + j + someConstant(); }
double someConstant() && { return 10; }
double someConstant() & { return 100; }
};
int main() {
Experiment E(3, 5);
std::cout << std::move(E).sum() << "\n"; // prints: 108
std::cout << E.sum() << "\n"; // prints: 108
}
This output seems expected if we consider that *this object inside the member function double sum() is always either an lvalue or xvalue (thus a glvalue) . Please confirm if this is true or not.
How can we perfectly forward *this object to the member function call someConstant() inside the double sum() member function?
I tried using std::forward as follows:
double sum() {
return i + j + std::forward<decltype(*this)>(*this).someConstant();
}
But this did not have any effect, and double someConstant() & overload is the one always being called.
This is not possible in C++11 without overloading sum for & and && qualifiers. (In which case you can determine the value category from the qualifier of the particular overload.)
*this is, just like the result of any indirection, a lvalue, and is also what an implicit member function call is called on.
This will be fixed in C++23 via introduction of an explicit object parameter for which usual forwarding can be applied: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html
One would think that std::forward() would preserve lvalue references but it doesn't in non-template contexts, as the example below shows.
Both call_f()& and call_f()&& call f()&&. std::forward<Experiment>(*this) in a non-template function returns an rvalue reference regardless of the value category of the argument.
Note how this works differently from a template function, member or not (I made the member function static because it receives a "this reference" as an explicit parameter) . Both forward lvalue references "properly" (the last 4 calls).
#include<iostream>
#include<utility>
#include<string>
struct Experiment
{
public:
std::string f()&& { return "f()&&"; }
std::string f()& { return "f()&"; }
std::string call_f()&& { std::cout << "call_f()&& "; return std::forward<Experiment>(*this).f(); }
// I need this function because it is not a template function
std::string call_f()& { std::cout << "call_f()& "; return std::forward<Experiment>(*this).f(); }
template<class T = Experiment>
static std::string E_t_call_f(T&& t) { std::cout << "E_t_call_f(T&& t) "; return std::forward<T>(t).f(); }
};
template<class T>
std::string t_call_f(T&& t) { std::cout << "t_call_f(T&& t) "; return std::forward<T>(t).f(); }
int main()
{
Experiment E;
std::cout << "E.f(): " << E.f() << '\n';
std::cout << "move(E).f(): " << std::move(E).f() << '\n';
std::cout << '\n';
std::cout << "E.call_f(): " << E.call_f() << '\n';
std::cout << "move(E).call_f(): " << std::move(E).call_f() << '\n';
std::cout << '\n';
std::cout << "t_call_f(E): " << t_call_f(E) << '\n';
std::cout << "t_call_f(std::move(E)): " << t_call_f(std::move(E)) << '\n';
std::cout << '\n';
std::cout << "E::E_t_call_f(E): " << Experiment::E_t_call_f(E) << '\n';
std::cout << "E::E_t_call_f(std::move(E)): " << Experiment::E_t_call_f(std::move(E)) << '\n';
}
In the resulting output it is the third line that's surprising: The type of std::forward<Experiment>(*this) for an lvalue reference to *this is an rvalue reference.
E.f(): f()&
move(E).f(): f()&&
call_f()& E.call_f(): f()&&
call_f()&& move(E).call_f(): f()&&
t_call_f(T&& t) t_call_f(E): f()&
t_call_f(T&& t) t_call_f(std::move(E)): f()&&
E_t_call_f(T&& t) E::E_t_call_f(E): f()&
E_t_call_f(T&& t) E::E_t_call_f(std::move(E)): f()&&
I have always found iomanip confusing and counter intuitive. I need help.
A quick internet search finds (https://www.vedantu.com/maths/precision) "We thus consider precision as the maximum number of significant digits after the decimal point in a decimal number" (the emphasis is mine). That matches my understanding too. However I wrote a test program and:
stm << std::setprecision(3) << 5.12345678;
std::cout << "5.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 25.12345678;
std::cout << "25.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 5.1;
std::cout << "5.1: " << stm.str() << std::endl;
stm.str("");
outputs:
5.12345678: 5.12
25.12345678: 25.1
5.1: 5.1
If the precision is 3 then the output should be:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
Clearly the C++ standard has a different interpretation of the meaning of "precision" as relates to floating point numbers.
If I do:
stm.setf(std::ios::fixed, std::ios::floatfield);
then the first two values are formatted correctly, but the last comes out as 5.100.
How do I set the precision without padding?
You can try using this workaround:
decltype(std::setprecision(1)) setp(double number, int p) {
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0 && e > 1)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
return std::setprecision(e);
}
And then:
auto v = 5.12345678;
stm << setp(v, 3) << v;
Another more verbose and elegant solution is to create a struct like this:
struct __setp {
double number;
bool fixed = false;
int prec;
};
std::ostream& operator<<(std::ostream& os, const __setp& obj)
{
if(obj.fixed)
os << std::fixed;
else os << std::defaultfloat;
os.precision(obj.prec);
os << obj.number; // comment this if you do not want to print immediately the number
return os;
}
__setp setp(double number, int p) {
__setp setter;
setter.number = number;
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
if(e <= 0) {
setter.fixed = true;
setter.prec = 1;
} else
setter.prec = e;
return setter;
}
Using it like this:
auto v = 5.12345678;
stm << setp(v, 3);
I don't think you can do it nicely. There are two candidate formats: defaultfloat and fixed. For the former, "precision" is the maximum number of digits, where both sides of the decimal separator count. For the latter "precision" is the exact number of digits after the decimal separator.
So your solution, I think, is to use fixed format and then manually clear trailing zeros:
#include <iostream>
#include <iomanip>
#include <sstream>
void print(const double number)
{
std::ostringstream stream;
stream << std::fixed << std::setprecision(3) << number;
auto string=stream.str();
while(string.back()=='0')
string.pop_back();
if(string.back()=='.') // in case number is integral; beware of localization issues
string.pop_back();
std::cout << string << "\n";
}
int main()
{
print(5.12345678);
print(25.12345678);
print(5.1);
}
The fixed format gives almost what you want except that it preserves trailing zeros. There is no built-in way to avoid that but you can easily remove those zeros manually. For example, in C++20 you can do the following using std::format:
std::string format_fixed(double d) {
auto s = fmt::format("{:.3f}", d);
auto end = s.find_last_not_of('0');
return end != std::string::npos ? std::string(s.c_str(), end + 1) : s;
}
std::cout << "5.12345678: " << format_fixed(5.12345678) << "\n";
std::cout << "25.12345678: " << format_fixed(25.12345678) << "\n";
std::cout << "5.1: " << format_fixed(5.1) << "\n";
Output:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
The same example with the {fmt} library, std::format is based on: godbolt.
Disclaimer: I'm the author of {fmt} and C++20 std::format.
I have to construct an ordered container (which must be iterable) with the following rule:
If the condition is true, the container is {1,0}, else it's {0,1}
I have the following code, but I don't find it "elegant":
vector<int> orderedSides;
if (condition)
{
orderedSides.push_back(1);
orderedSides.push_back(0);
}
else
{
orderedSides.push_back(0);
orderedSides.push_back(1);
}
Is there a better way to do this (from concision and performance point of view)?
You might implement something like this:
vector<int> orderedSides(2, 0);
(condition ? orderedSides.front() : orderedSides.back()) = 1;
which is a little bit shorter than explicit if clauses.
As #Deduplicator mentioned below, we might rewrite the second line in a more concise way:
orderedSides[!condition] = 1;
vector<int> orderedSides;
orderedSides.push_back(condition ? 1 : 0);
orderedSides.push_back(condition ? 0 : 1);
I don't think it's more performant but I find it more elegant.
You could compromise between efficiency and avoiding repetition, initialise the first with the condition and the second from the first.
vector<int> orderedSides(1, bool(condition)) ;
orderedSides.push_back(!orderedSides.back());
orderedSides.push_back(0);
orderedSides.push_back(1);
if (condition)
std::iter_swap(orderedSides.begin(), orderedSides.begin()+1);
I know this take bits cost. As one of candidates.
If building the elements (the ints in your question, whatever it is in real life) is free and side-effect-less:
static const int data[] = { 0, 1, 0 };
std::vector<int> orderedSides (data+condition, data+condition+2);
Full program example:
#include <iostream>
#include <vector>
std::vector<int> make(bool cond)
{
static const int data[] = { 0, 1, 0 };
return std::vector<int> (data+cond, data+cond+2);
}
std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
{
return os << "{ " << v[0] << ", " << v[1] << " }";
}
int main()
{
std::cout << "true: " << make(true) << "\n"
<< "false: " << make(false) << "\n";
}
Prints:
true: { 1, 0 }
false: { 0, 1 }
Demo
You can populate a std::vector from an array, even in C++98.
Here's an example:
#include <iostream>
#include <vector>
int main() {
bool condition = false;
std::cout << "condition is: " << std::boolalpha << condition << '\n';
int arr[][2] = {{0,1}, {1,0}};
int index = condition;
std::vector<int> v(arr[index], arr[index]+2);
for (int i = 0; i < v.size(); i++)
std::cout << v[i] << ' ';
std::cout << '\n';
}
The output is:
$ g++ tt.cc && ./a.out
condition is: false
0 1
For reference:
http://en.cppreference.com/w/cpp/container/vector/vector
So I'm working with operator overloading and just realized that my negation operator isn't working as it should be. I'm not exactly sure what I've done wrong.
The .h signature
Vector & Vector::operator-()
The .cpp implementation
Vector & Vector::operator-()
{
pVec[0] = -pVec[0];
pVec[1] = -pVec[1];
pVec[2] = -pVec[2];
return *this;
};
Calling:
cout << "-Vector E = " << -VecE << (-VecE).Magnitude() << endl << endl;
The variables in VecE are like [0, 1 , 1] which means when this is called it should display them as [0, -1, -1] but it's not. So what am I missing?
EDIT: Adding copy constructor and iostream<< overload code:
Vector::Vector(const Vector & Copy)
{
pVec = new double[3];
if (0 == pVec)
{
exit(1);
}
else
{
pVec[0] = Copy.pVec[0];
pVec[1] = Copy.pVec[1];
pVec[2] = Copy.pVec[2];
}
};
ostream & operator<<(ostream & Out, Vector & RHS)
{
cout.precision(1);
Out << fixed << "[ " << RHS.pVec[0] << " " << RHS.pVec[1] << " " << RHS.pVec[2] << " ]" << resetiosflags (ios_base::fixed);
return Out;
};
You need to return a copy of the vector. The way this is written, the expression -VecE will actually modify VecE! Since you evaluate -VecE twice, you are negating the vector twice, and (of course) the negation of the negation is the original value.
To implement this change, you need to alter the operator-() declaration to return a Vector instead of a Vector &.
For example:
Vector Vector::operator-()
{
Vector copy(*this);
copy.pVec[0] = -copy.pVec[0];
copy.pVec[1] = -copy.pVec[1];
copy.pVec[2] = -copy.pVec[2];
return copy;
};
cdhowie is right. You are negating twice.
That said, I don't think you need to change the implementation.
Vector const NegVecE = -VecE;
cout << "-Vector E = " << NegVecE << NegVecE.Magnitude() << endl << endl;
EDIT: As PiotrNycz notes, though this will work, the end state is un-intuitive and therefore the correct solution is to return a copy.
{
int i = 3;
int j = -i; //you would expect i to still be 3 here
}
I have overloaded [] operator in my class Interval to return minutes or seconds.
But I am not sure how to assign values to minutes or second using [] operator.
For example : I can use this statement
cout << a[1] << "min and " << a[0] << "sec" << endl;
but I want to overload [] operator, so that I can even assign values to minutes or seconds using
a[1] = 5;
a[0] = 10;
My code :
#include <iostream>
using namespace std;
class Interval
{
public:
long minutes;
long seconds;
Interval(long m, long s)
{
minutes = m + s / 60;
seconds = s % 60;
}
void Print() const
{
cout << minutes << ':' << seconds << endl;
}
long operator[](int index) const
{
if(index == 0)
return seconds;
return minutes;
}
};
int main(void)
{
Interval a(5, 75);
a.Print();
cout << endl;
cout << a[1] << "min and " << a[0] << "sec" << endl;
cout << endl;
}
I know I have to declare member variables as private, but I have declared here as public just for my convenience.
Return a reference to the member in question, instead of its value:
long &operator[](int index)
{
if (index == 0)
return seconds;
else
return minutes;
}
Change the function signature by removing the const and returning a reference:
long& operator[](int index)
Now you will be able to write statements like:
a[0] = 12;
Overloading op[] to use hardcoded "index" values doesn't make sense here, and you actually already have the solution in your class definition:
cout << a.minutes << "min and " << a.seconds << "sec" << endl;
You can turn those into methods instead of public data members, that's inconsequential for not overloading op[]. However, since you want write access as well, the only advantage a method would have is validation (e.g. checking 0 <= seconds < 60).
struct Interval {
int minutes() const { return _minutes; }
void minutes(int n) { _minutes = n; } // allows negative values, etc.
int seconds() const { return _seconds; }
void seconds(int n) {
if (0 <= n and n < 60) {
_seconds = n;
}
else {
throw std::logic_error("invalid seconds value");
}
}
// rest of class definition much like you have it
private:
int _minutes, _seconds;
};
// ...
cout << a.minutes() << "min and " << a.seconds() << "sec" << endl;
return by reference to be able to assign values and use them on the LHS of the assignment operator.
converting the method to as given below should do it:
long& operator[](int index)
Your array index member operator should be provided as
long& operator[](int index); // for non const object expressions
long const& operator[](int index) const; // for const object expressions
In-order to avoid confusion in the case of overloading the sub-script operator, it is recommended to use the const and non-const version of the sub-script operator.
long& operator[](int index); // non-const function returning reference
long const& operator[](int index) const;// const function returning const reference
With A[1] = 5, you are trying to modify the object at index 1. So the non-const version of the sub-script operator will be invoked automatically.
With cout << A[1], you are not modifying the object at index 1. So the const version of the sub-script operator will be invoked automatically.