jayjay
jayjay

Reputation: 1047

C++ Printing an object in multiple ways

If I take a simple date object:

#include <iostream>
using namespace std;

class Date
{
    int mo, da, yr;
public:
    Date(int m, int d, int y)
    {
        mo = m; da = d; yr = y;
    }
    friend ostream& operator<<(ostream& os, const Date& dt);
};

ostream& operator<<(ostream& os, const Date& dt)
{
    os << dt.mo << '/' << dt.da << '/' << dt.yr;
    return os;
}

int main()
{
    Date dt(5, 6, 92);
    cout << dt;
}

and I wish to have the option to print it in a way people from the UK will understand i.e.

ostream& operator<<(ostream& os, const Date& dt)
{
    os << dt.da << '/' << dt.mo << '/' << dt.yr;
    return os;
}

How is the best way to allow users of the class to choose between 2 (or more) print options?

I was thinking of something similar to returning two separate classes from two methods of the date class that each have their operator<< overloaded in the 2 different ways. But Is there a better way?

code from: http://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx

Upvotes: 4

Views: 404

Answers (2)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48517

A culture-dependent stream formatting (such as for dates, monetary) should base on std::locale settings of a given stream:

#include <locale>
#include <ostream>

std::ostream& operator<<(std::ostream& os, const Date& dt)
{
    std::time_base::dateorder d = std::use_facet<std::time_get<char>>(os.getloc())
                                      .date_order();

    if (d == std::time_base::dmy)
    {
        // Selected format is day / month / year
        os << dt.da << '/' << dt.mo << '/' << dt.yr;
    }
    else if (d == std::time_base::mdy)
    {
        // Selected format is month / day / year
        os << dt.mo << '/' << dt.da << '/' << dt.yr;
    }
    else
    {
        // Default format is year . month . day
        os << dt.yr << '.' << dt.mo << '.' << dt.da;
    }

    return os;
}

This allows users of your class to select between different formats (assuming the locale are supported), so that the output is adjusted for a given culture:

Date d{ 9, 8, 2014 };

std::cout.imbue(std::locale("en_US.utf8"));
std::cout << d << std::endl;

std::cout.imbue(std::locale("de_DE.utf8"));
std::cout << d << std::endl;

DEMO

Upvotes: 9

user3458
user3458

Reputation:

You need to implement a manipulator.

I am sure there is support in C++ for implementing your own. For inspiration, have a look at how, say, std::showbase/std::noshowbase is implemented in your environment. You'd need to implement ukdate/noukdate .

Edit: showbase is indeed too narrow example for this - we'd need to allocate per-stream word using std::ios_base::xalloc.

Upvotes: 4

Related Questions