I've got a simple class Currency with overloaded operator<<. I don't know how can i separate the number with spaces every 3 digits, so it looks like: "1 234 567 ISK".
#include <cstdlib>
#include <iostream>
using namespace std;
class Currency
{
int val;
char curr[4];
public:
Currency(int _val, const char * _curr)
{
val = _val;
strcpy(curr, _curr);
}
friend ostream & operator<< (ostream & out, const Currency & c);
};
ostream & operator<< (ostream & out, const Currency & c)
{
out << c.val<< " " << c.curr;
return out;
}
int main(int argc, char *argv[])
{
Currency c(2354123, "ISK");
cout << c;
}
What interests me, is somehow the easiest solution for this particular situation.
This can be done with facets
struct myseps : numpunct<char> {
/* use space as separator */
char do_thousands_sep() const { return ' '; }
/* digits are grouped by 3 digits each */
string do_grouping() const { return "\3"; }
};
int main() {
std::cout.imbue(std::locale(std::locale(), new myseps));
std::cout << 10000; // 10 000
}
Alternatively, you may code your own loop
void printGrouped(ostream &out, int n) {
if(n < 0) {
out << "-";
return printGrouped(out, -n);
}
if(n < 1000) {
out << n;
} else {
printGrouped(out, n / 1000);
out << " " << setw(3) << setfill('0') << (n % 1000);
}
}
ostream & operator<< (ostream & out, const Currency & c) {
printGrouped(out, c.val);
out << " " << c.curr;
return out;
}
One possibility might be to use locales for this.
#include <locale>
#include <string>
#include <cstddef>
class SpaceSeparator: public std::numpunct<char>
{
public:
SpaceSeparator(std::size_t refs): std::numpunct<char>(refs) {}
protected:
char do_thousands_sep() const { return ' '; }
std::string do_grouping() const { return "\03"; }
};
//...
ostream & operator<< (ostream & out, const Currency & c)
{
SpaceSeparator facet(1); //1 - don't delete when done
std::locale prev = out.imbue(std::locale(std::locale(), &facet));
out << c.val<< " " << c.curr;
out.imbue(prev); //restore previous locale
return out;
}
struct Currency {
static char const sep = ' ';
static int const group_size = 3;
Currency(int val, std::string unit)
: val(val), unit(unit)
{}
friend std::ostream& operator<<(std::ostream& out, Currency const& v) {
// currently ignores stream width and fill
std::ostringstream ss;
bool const neg = v.val < 0;
int const val = (neg ? -v.val : v.val);
if (neg) out << '-';
ss << val;
std::string const s = ss.str();
std::string::size_type n = s.size() % v.group_size;
if (n) out << s.substr(0, n);
for (; n < s.size(); n += v.group_size) {
out << sep << s.substr(n, v.group_size);
}
out << ' ' << v.unit;
return out;
}
private:
int val;
std::string unit;
};
Could make sep and group_size non-static members, if you want to customize each object with comma, etc. (If so, make them private and initialize in the ctor, probably with default parameter values.) You could also use a traits class controlling output formatting.
Locales also support currency formatting through the moneypunct facet.
#include <iostream>
#include <sstream>
#include <cstdlib>
#define GROUP_SEP ','
#define GROUP_SIZE 3
using namespace std;
string output_formatted_string(long long num);
int main() {
string temp;
cout << "Enter a large number: ";
getline(cin, temp);
long long num = atoll(temp.c_str());
string output = output_formatted_string(num);
cout << output << endl;
return 0;
}
string output_formatted_string(long long num)
{
stringstream temp, out;
temp << num;
string s = temp.str();
int n = s.size() % GROUP_SIZE;
int i = 0;
if(n>0 && s.size() > GROUP_SIZE)
{
out << s.substr(i, n) << GROUP_SEP;
i += n;
}
n = s.size() / GROUP_SIZE - 1;
while(n-- > 0)
{
out << s.substr(i, GROUP_SIZE) << GROUP_SEP;
i += GROUP_SIZE;
}
out << s.substr(i);
return out.str();
}
Related
I have the following class:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
struct
{
string HEX() { return Number + " - HEX"; }
string DEC() { return Number + " - DEC"; }
string BIN() { return Number + " - BIN"; }
}ToString;
private:
string Number;
};
And in the end I wand to elegantly access functions from that structure in the following way:
BigNum a = "1234";
cout << "a = " << a.ToString.DEC() << endl;
cout << "b = " << a.ToString.HEX() << endl;
The problem here is that I cannot access variable Number from my structure.
I know that something like this would solve my problem:
struct
{
string HEX(BigNum &parent) { return parent.Number + " - HEX"; }
...
}ToString;
The problem with this solution is that it is not comfortable to always pass a pointer to my instance.
What would be a solution in this case to have data in nested class and in the same time to keep calls as simple as a.ToString.DEC()?
In some way you have to give ToString a reference or a pointer to the BigNum object so you can access Number. How about something like this:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char* StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
// you can make the struct private so the type is not visible externally
struct ToStringType
{
private:
const BigNum& ref;
public:
ToStringType(const BigNum& r) : ref(r) {}
string HEX() { return ref.Number + " - HEX"; }
string DEC() { return ref.Number + " - DEC"; }
string BIN() { return ref.Number + " - BIN"; }
};
ToStringType ToString{ *this };
private:
string Number;
};
Irrelevant, but I would recommend to simply have separate ToStringHex, ToStringDec and ToStringBin functions. Saves on not storing a reference, plus the API is easier this way.
I don't see any rationale in the ToString struct.
Just leave the methods in BIGNUM and you are done.
However, for this specific application (changing the rendering style of your given objet in an ostream) I would let your object to be printed with the typical operator<< overaloading, and then modify the rendering style using io-manipulators, so that you will be able to:
cout << "a (DEC) = " << BigNum::DEC << a << endl;
cout << "a (HEX) = " << BigNum::HEX << a << endl;
A full fledged example:
#include <iostream>
#include <iomanip>
using namespace std;
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
static std::ios_base& DEC(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 0;
return os;
}
static std::ios_base& HEX(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 1;
return os;
}
static std::ios_base& BIN(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 2;
return os;
}
private:
static int rendering_style_xalloc;
string Number;
friend ostream &operator << (ostream &ostr, const BigNum &bignum);
};
int BigNum::rendering_style_xalloc = std::ios_base::xalloc();
ostream &operator << (ostream &os, const BigNum &bignum) {
switch (os.iword(BigNum::rendering_style_xalloc)) {
case 0:
os << bignum.Number << " - DEC";
break;
case 1:
os << bignum.Number << " - HEX";
break;
case 2:
os << bignum.Number << " - BIN";
break;
default:
os << bignum.Number << " - UNK";
break;
}
return os;
}
int main(int argc, char **argv)
{
BigNum a = "1234";
cout << BigNum::DEC << "a (DEC) = " << a << endl;
cout << BigNum::HEX << "a (HEX) = " << a << endl;
}
References:
https://en.cppreference.com/w/cpp/io/ios_base/iword
This program uses class and takes the info of employees from a file. I have mentioned the file below too. I have also mentioned the output i received even though there are error. There is something wrong in the output too but I think it is because of the info error that it's getting.
While running this program, I got this error message:
Error: Run-Time Check Failure #2 - Stack around the variable 'info' was corrupted.
There's also this message:
Unhandled exception at 0x00950A89 in employee.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.
// The used file for this program is:
A.Smith 20001 25 40
T.Philip 20002 20 35
S.LOng 20003 15 50
G.Santos 20004 30 30
F.Farkas 20005 22 55
// The output after running even with the errors is:
This week's employee history
Name Id Rate Hours
* A.Smith 20001 $25/h 40h
* T.Philip 20002 $20/h 35h
* S.LOng 20003 $15/h 50h
* G.Santos 20004 $30/h 30h
* F.Farkas 20005 $22/h 55h
This week's payment
Name Payment
* ╠╠╠╠╠╠╠╠ $0 <----------There is this error too
* T.Philip $700
* S.LOng $825
* G.Santos $900
* A.Smith $1000
* The average wages of the employees: $685.00
// The code is:
/*
#include "pch.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include<iomanip>
*/
using namespace std;
struct records {
char name[50] = {};
char id[5] = {};
int rate = 0;
int hours = 0;
int pay = 0;
};
void take(records array[], const int a);
int calculator(records array[], const int a);
void swap(records array[], const int a);
double Average(records array[], int a);
ifstream infile;
int main()
{
const int n = 5;
This is the first time info is declared:
struct records info[n];
double averageWages;
int overTime = 0, i;
infile.open("Project 3.dat");
cout << "\n This week's employee history \n" << endl;
if (infile.is_open()) {
cout << " Name Id Rate Hours " << endl;
Here take function uses info of the struct:
take(info, n);
cout << endl << endl;
cout << "This week's payment\n" << endl;
cout << " Name Payment" << endl;
Also here other functions use info:
calculator(info, n);
swap(info, n);
for (i = 0; i < n; i++) {
cout << "*" << setw(10) << info[i].name << setw(10) << "$" << info[i].pay << endl;
}
averageWages = Average(info, n);
cout << "\n\n" << "* The average wages of the employees: $" << averageWages << endl << endl;
}
else {
cerr << "Error! file cannot open." << endl;
exit(1);
}
return 0;
}
// Taking records:
void take(records array[], const int a) {
for (int i = 0; i < a; i++) {
while (infile >> array[i].name >> array[i].id >> array[i].rate >> array[i].hours) {
cout << "*" << setw(9) << array[i].name << setw(10) << array[i].id << setw(10) << "$" << array[i].rate << "/h" << setw(10) << array[i].hours << "h " << endl;
}
} infile.close();
}
//swap records to arrange it according to total payment received
void swap(records array[], const int a) {
bool tf; //true or false
do {
tf = false;
for (int i = 0; i < a; i++) {
if (array[i].pay > array[i + 1].pay) {
swap(array[i], array[i + 1]);
tf = true;
}
}
} while (tf);
records temp;
for (int i = 0; i < a - 1; ++i)
{
for (int j = i + 1; j < a; ++j)
{
if (array[i].pay > array[j].pay)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
To calculate average:
double Average(records array[], const int a) {
double total = 0;
double average;
for (int i = 0; i < a; i++) {
total = total + (array[i].pay);
average = total / a;
}
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);
return (total / a);
}
// To calculate the salary:
int calculator(records array[], const int a) {
infile.open("Project 3.dat");
if (infile.is_open()) {
for (int i = 0; i < a; i++) {
infile >> array[i].name >> array[i].id >> array[i].rate >> array[i].hours;
if (array[i].hours > 40) {
int overTime = (array[i].hours - 40)*1.5;
array[i].pay = ((array[i].rate) * 40) + (overTime*(array[i].rate));
}
else {
array[i].pay = (array[i].rate)*(array[i].hours);
}
}
for (int i = 0; i < a; i++) {
return (array[i].pay);
}
}
}
It's hard to find all potential problems with that fragmented code, but you'd be better off using std::strings instead of char[]. They are safer and also has a lot of built-in functions. They also work well with misc. functions in the STL.
Your struct records info[n]; will only hold n (5) elements. Use a standard container, like a std::vector instead in case you'd like to add more entries to the file.
Reading and writing to files can usually be done using custom stream operators and all the free functions you have to deal with a number of records could be collected in a class of its own. I've made one record struct and one Records class to demonstrate how they could be used Together.
#include <iostream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <numeric>
#include <algorithm>
#include <functional>
struct record {
std::string name{};
std::string id{};
int rate = 0;
int hours = 0;
int pay = 0;
// stream operators for reading/writing a record
friend std::istream& operator>>(std::istream&, record&);
friend std::ofstream& operator<<(std::ofstream&, const record&);
friend std::ostream& operator<<(std::ostream&, const record&);
};
// populate a record from an istream
std::istream& operator>>(std::istream& is, record& r) {
std::string line;
// get a line and check that it's > 30 chars long
if(std::getline(is, line) && line.size()>30) {
// extract the name and remove trailing spaces
r.name = line.substr(0, 30);
auto pos = r.name.find_last_not_of(' ');
if(pos != std::string::npos)
r.name = r.name.substr(0, pos+1);
// put the rest of the line in a stringstream
std::stringstream ss(line.substr(30));
// and extract the rest of the fields
if(ss >> r.id >> r.rate >> r.hours) {
// calculate pay
r.pay = r.rate * r.hours;
} else { // if extraction fails, set the stream in fail mode
is.setstate(std::ios_base::failbit);
}
} else is.setstate(std::ios_base::failbit);
return is;
}
// streaming a record to an ofstream (like a file)
std::ofstream& operator<<(std::ofstream& os, const record& r) {
os << std::setw(30) << std::left << r.name.substr(0, 30) << r.id << " " << r.rate << " " << r.hours << "\n";
return os;
}
// streaming a record to a generic ostream (like std::cout)
std::ostream& operator<<(std::ostream& os, const record& r) {
os << "* " << std::setw(30) << std::left << r.name << std::right << r.id
<< " $" << r.rate << "/h " << r.hours << "h $" << std::setw(4) << r.pay;
return os;
}
class Records { // a class to maintain a number of "record"s
std::vector<record> m_records{}; // stores all "record"s
public:
Records(const std::string& filename) {
record tmp;
std::ifstream e(filename); // open file
// and extract one record at a time and put it in m_records.
while(e>>tmp) m_records.emplace_back(std::move(tmp));
}
// sum on any member in "record"
template <typename field>
auto Sum(field f) const {
return std::accumulate(m_records.begin(), m_records.end(), 0,
[&](int a, const record& b) { return a + (b.*f); });
}
// average of any member in "record"
template <typename field>
auto Average(field f) const {
return static_cast<double>(Sum(f)) / m_records.size();
}
// sorting on any member in "record"
template <typename field, typename T>
void Sort(field f, const T& cmp) {
std::sort(m_records.begin(), m_records.end(),
[&](const record& a, const record& b){ return cmp(a.*f, b.*f); });
}
// return the number of "record" elements
std::vector<record>::size_type size() const { return m_records.size(); }
// access an element via subscript
record& operator[](std::vector<record>::size_type idx) { return m_records[idx]; }
const record& operator[](std::vector<record>::size_type idx) const { return m_records[idx]; }
// iterators to use in for-loops
std::vector<record>::const_iterator cbegin() const noexcept { return m_records.cbegin(); }
std::vector<record>::const_iterator cend() const noexcept { return m_records.cend(); }
std::vector<record>::const_iterator begin() const noexcept { return cbegin(); }
std::vector<record>::const_iterator end() const noexcept { return cend(); }
std::vector<record>::iterator begin() noexcept { return m_records.begin(); }
std::vector<record>::iterator end() noexcept { return m_records.end(); }
// stream operator to show all records
friend std::ostream& operator<<(std::ostream&, const Records&);
};
std::ostream& operator<<(std::ostream& os, const Records& R) {
os << " Name Id Rate Hrs Pay\n";
for(const auto& r : R) std::cout << r << "\n";
os << std::setprecision(2) << std::fixed;
os << "Average pay : $" << std::setw(7) << R.Average(&record::pay) << "\n";
os << " rate : $" << std::setw(7) << R.Average(&record::rate) << "\n";
os << " hours worked: " << std::setw(7) << R.Average(&record::hours) << "h\n";
return os;
}
int main() {
// create a "Records" entity called "info" by reading a file
Records info("Project 3.dat");
// misc sorting and showing the result
std::cout << "Sorted as read from the file:\n";
std::cout << info;
std::cout << "\nSorted according to name:\n";
info.Sort(&record::name, std::less<std::string>());
std::cout << info;
std::cout << "\nSorted according to id:\n";
info.Sort(&record::id, std::less<std::string>());
std::cout << info;
std::cout << "\nSorted according to pay:\n";
info.Sort(&record::pay, std::greater<int>());
// output example using iterators:
for(auto& rec : info) {
std::cout << rec << "\n";
}
std::cout << "\nSorted according to rate:\n";
info.Sort(&record::rate, std::greater<int>());
std::cout << info;
std::cout << "\nSorted according to hours:\n";
info.Sort(&record::hours, std::greater<int>());
std::cout << info;
// example using subscript, operator[]
if(info.size()>2) {
std::cout << "\ninfo[2] = " << info[2] << "\n";
}
}
This is the photo of the model I have to resolve:
I have this class:
#include<iostream>
#include<fstream>
using namespace std;
class Word
{
protected:
char *value;
char type[20];
int noChars;
static int noWords;
public:
Word(char *value, char *type)
{
this->noChars = 0;
this->value = new char[strlen(value) + 1];
strcpy(this->value, value);
strcpy(this->type, type);
Word::noWords++;
}
Word()
{
this->noChars = NULL;
this->value = NULL;
strcpy(this->type,"Nedeterminat");
}
void operator=(Word &x)
{
this->noChars = x.noChars;
strcpy(this->type, x.type);
this->value = new char[strlen(x.value) + 1];
strcpy(this->value, x.value);
}
Word(const Word& x){
this->noChars = x.noChars;
strcpy(this->type, x.type);
this->value = new char[strlen(x.value) + 1];
strcpy(this->value, x.value);
}
char* getValue()
{
return this->value;
}
void setType(char* x)
{
if (x == NULL)
{
throw new exception("Tip gresit!");
}
else
{
strcpy(this->type, x);
}
}
char &operator[](int i)
{
if (i >= 0 && i <= (strlen(this->value) - 1))
{
return this->value[i];
}
else
cout << endl << "Eroare indice: " << i;
}
static int getNoWords()
{
return Word::noWords;
}
operator int()
{
return this->noChars;
}
friend ostream& operator<<(ostream&, Word&);
friend istream& operator>>(istream&, Word&);
};
ostream& operator<<(ostream& consola, Word& x)
{
consola << "Value: " << x.getValue() << endl;
consola << "Type: " << x.type << endl;
consola << "NoChars: " << x.noChars << endl;
return consola;
}
istream& operator>>(istream& consola, Word& x){
cout << "Value: "; consola >> x.value;
cout << "Type: "; consola >> x.type;
cout << "NoChars: "; consola >> x.noChars;
return consola;
}
int Word::noWords = 0;
class Dictionary{
private:
char *language;
int noWords;
bool isOnline;
Word v[100];
public:
Dictionary(char *language, Word w, int noWords, bool isOnline)
{
this->language = new char[strlen(language) + 1];
strcpy(this->language, language);
for (int i = 0; i < 100; i++)
{
this->v[i] = w;
}
this->noWords = noWords;
this->isOnline = isOnline;
}
};
int main()
{
//1
Word w1("exam", "noun");
/*Word w2;*/
Word w3 = w1;
cout << w3;
//2
cout << endl << "Word value: " << w3.getValue();
Word w2("to take", "noun");
w2.setType("verb");
//3
w3 = w2;
cout << endl << w3;
Word *pw = new Word("pointer", "noun");
delete pw;
//4
cin >> w3; cout << w3;
char character = w3[2];
cout << endl << character;
//5
double noChars = (int)w1;
cout << endl << noChars;
cout << endl << Word::getNoWords() << endl;
//6
Dictionary dictionary1("English", NULL, 0, false);
}
I have this main:
Dictionary dictionary1("English", NULL, 0, false);
How should I change the constructor to work? I receive a error :
Arrgument types are:(const char[8],int,int,bool);
And how should I write the default constructor?
NULL cannot be assigned to Word. Try Word() instead which will call the default constructor to Word. Consider changing that function parameter to const Word& - anonymous temporaries are allowed to bind to const references.
I'd prefer to see a std::string as the type for the member variable language; using a const std::string& as the function parameter. Then you will not have to worry about a subsequent delete call, and defining your own assignment operators and copy constructors. Currently, your class leaks memory.
You can not Assign null to the type Word. If you want to default it you should pass something like word()
Dictionary dictionary1("English", word(), 0, false);
EDIT:
The better approach,IMO, that will work for the same main() you have is like this:
class Dictionary{
private:
std::string language;
int noWords;
bool isOnline;
std::array<Word,100> v;
public:
Dictionary(std::string const& language, Word* w, int noWords, bool isOnline): language (language),isOnline(isOnline ),noWords(noWords)
{
for (int i = 0; i < 100; i++){
this->v[i] = (w==NULL)?word():*w;
}
}
};
This question already has answers here:
How can I print 0x0a instead of 0xa using cout?
(9 answers)
Closed 6 years ago.
Say I have a dword I want to output in hex with std::cout and left-pad with zeros, so 0xabcd will be shown as 0x0000abcd. It seems like you would have to do this:
uint32_t my_int = 0xabcd;
std::cout << "0x" << std::hex << std::setw(8) << std::setfill('0')
<< my_int << std::endl;
This seems ridiculous for something that can be accomplished in C with printf("0x%08X\n", my_int);. Is there any way to make this shorter while still using std::cout for output (besides using namespace std)?
I suppose you can write a "stream manipulator". This is useful if you have multiple hex numbers you want to print in this format. This is clearly not an ideal solution, but using a wrapper type you can make your own "format flag" to toggle it. See Sticky custom stream manipulator for more information.
#include <iostream>
#include <iomanip>
static int const index = std::ios_base::xalloc();
std::ostream& hexify(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}
std::ostream& nohexify(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}
struct WrapperType {
uint32_t _m;
public:
WrapperType(uint32_t m) : _m(m)
{
}
uint32_t getm() const
{
return _m;
}
};
std::ostream& operator<< (std::ostream& os, const WrapperType& t) {
if (os.iword(index))
return os << "0x" << std::hex << std::setw(8) << std::setfill('0') << t.getm();
else
return os << t.getm();
}
int main()
{
WrapperType my_int{0xabcd};
std::cout << hexify << my_int << my_int;
std::cout << nohexify << my_int;
}
I would not change the (global) flags of a stream, just a manipulator:
#include <iostream>
#include <iomanip>
#include <limits>
template <typename T>
struct Hex
{
// C++11:
// static constexpr int Width = (std::numeric_limits<T>::digits + 1) / 4;
// Otherwise:
enum { Width = (std::numeric_limits<T>::digits + 1) / 4 };
const T& value;
const int width;
Hex(const T& value, int width = Width)
: value(value), width(width)
{}
void write(std::ostream& stream) const {
if(std::numeric_limits<T>::radix != 2) stream << value;
else {
std::ios_base::fmtflags flags = stream.setf(
std::ios_base::hex, std::ios_base::basefield);
char fill = stream.fill('0');
stream << "0x" << std::setw(width) << value;
stream.fill(fill);
stream.setf(flags, std::ios_base::basefield);
}
}
};
template <typename T>
inline Hex<T> hex(const T& value, int width = Hex<T>::Width) {
return Hex<T>(value, width);
}
template <typename T>
inline std::ostream& operator << (std::ostream& stream, const Hex<T>& value) {
value.write(stream);
return stream;
}
int main() {
std::uint8_t u8 = 1;
std::uint16_t u16 = 1;
std::uint32_t u32 = 1;
std::cout << hex(unsigned(u8), 2) << ", " << hex(u16) << ", " << hex(u32) << '\n';
}
My C++ is rusty, but how about using Boost formatting: http://www.boost.org/doc/libs/1_37_0/libs/format/index.html
How can I make my program output a number with at least one number behind the decimal mark C++?
Output:
1 = 1.0 or 1.25 = 1.25 or 2.2 = 2.2 or 3.456789 = 3.456789
Thanks in advance
Use showpoint to force the decimal point to be printed
double x = 1.0;
std::cout << std::showpoint << x << "\n";
It will be followed by the number of 0 required to satisfy the precision of the stream.
#include <cmath>
#include <iostream>
#include <limits>
struct FormatFloat
{
static constexpr const double precision = std::sqrt(std::numeric_limits<double>::epsilon());
const double value;
FormatFloat(double value) : value(value) {}
void write(std::ostream& stream) const {
std::streamsize n = 0;
double f = std::abs(value - (long long)value);
while(precision < f) {
f *= 10;
f -= (long long)f;
++n;
}
if( ! n) n = 1;
n = stream.precision(n);
std::ios_base::fmtflags flags = stream.setf(
std::ios_base::fixed,
std::ios_base::floatfield);
stream << value;
stream.flags(flags);
stream.precision(n);
}
};
inline std::ostream& operator << (std::ostream& stream, const FormatFloat& value) {
value.write(stream);
return stream;
}
inline FormatFloat format_float(double value) {
return FormatFloat(value);
}
int main()
{
std::cout
<< format_float(1) << '\n'
<< format_float(1.25) << '\n'
<< format_float(2.2) << '\n'
<< format_float(3.456789) << std::endl;
return 0;
}
If you're going to call this function a lot, then this probably isn't what you're looking for because this isn't the best way to do it, but it does work.
Something along the lines of:
string text = to_string(55);
if (text.find(".") != std::string::npos) {
cout << "No digit added after decimal point" << text;
}
else
{
cout << "Digit added after decimal point" << text << ".0";
}
double value = ...;
std::ostringstream ss;
ss.precision(std::numeric_limits<double>::digits10 + 2);
ss << value;
std::string s = ss.str();
if (s.find('.') == string::npos)
{
s.append(".0");
}
or
double value = ...;
std::wostringstream ss;
ss.precision(std::numeric_limits<double>::digits10 + 2);
ss << value;
std::wstring s = ss.str();
if (s.find(L'.') == string::npos)
{
s.append(L".0");
}