Re: How can I alter how a user-defined type/enum is displayed? (facet/locale?)
On 1 Jul., 17:02, Lorri <steve.lori...@gmail.com> wrote:
For a given user-defined type or enum:
eg:
enum blah
{
FOO,
BAR};
extern std::ostream& operator<<(std::ostream &out, const blah in);
extern const char* const prt(const blah in, const bool full = false);
How can I alter how the operator<< displays my blah enum? (in some
cases I want the full english name, whereas in other cases I want just
a single char)
At the moment I'm sort of getting what I want by using prt(my_blah,
true) or prt(my_blah, false)
eg:
const char* const prt(const blah in, const bool full)
{
switch (in)
{
case FOO: return full ? "FOO" : "F";
case BAR: return full ? "BAR" : "B";
default: break;
}
return full ? "UNKNOWN" : "?";
}
However, for operator<< I can't change how to print my blah enum
value.
eg:
std::ostream& operator<<(std::ostream &out, const blah in)
{
out << prt(in);
return out;
}
From what I've read online, I use a facet right? Then I have to imbue
the facet into std::ostream's locale or something? I have no idea how
to do this.
Can someone give me an example of a facet for a user-defined type, and
also how you then use it for std::cout or whatever?
First, your use-case description makes rather clear,
that you don't want to define a facet. Facets are used
to express locale-specific differences, but that is
not what you describe. What you want is so-called
manipulator. Manipulators are helper types that
introduce an indirection between a type and it's
output (or input) format.
To realize a manipulator, you will typically define
a helper type which is opaque for the user and a
helper function or functor that creates the helper
type. In your example it would be very easy to start
with something like this:
// Helper type
struct blah_manip_t {
blah value;
const char* foo_name;
const char* bar_name;
const char* err_name;
blah_manip_t(blah value, const char* foo_name, const char* bar_name,
const char* err_name) :
value(value), foo_name(foo_name), bar_name(bar_name),
err_name(err_name) {}
};
std::ostream& operator<<(std::ostream &out, blah_manip_t in) {
switch (in.value) {
case FOO: out << in.foo_name; break;
case BAR: out << in.bar_name; break;
default: out << in.err_name; break;
}
return out;
}
blah_manip_t full(blah value) {
return blah_manip_t(value, "FOO", "BAR", "UNKNOWN");
}
blah_manip_t short(blah value) {
return blah_manip_t(value, "F", "B", "?");
}
// Usage:
int main() {
blah val = ...;
std::cout << full(val) << " - " << short(val);
}
If you want to provide some default output, that is very easy:
std::ostream& operator<<(std::ostream &out, blah in) {
// Default output is full format:
return out << full(in);
}
More advanced ideas are possible, especially, if your
enum has much more enumerators, e.g. take advantage
of polymorphic manipulators:
class blah_manip_base_t {
blah value;
public:
explicit blah_manip_base_t(blah value) : value(value) {}
blah get_value() const { return value; }
virtual ~blah_manip_base_t(){}
virtual std::string get_name(blah) const = 0;
};
and define
std::ostream& operator<<(std::ostream &out, const blah_manip_base_t&
in) {
return out << in.get_name(in.value());
}
Or, if you want to reuse your approach via an existing
output function, you could keep a function pointer as
state within the manipulator, etc..
The last example just reuses your existing function prt
within a manipulator:
// Helper type
struct blah_manip_2_t {
blah value;
bool full;
blah_manip_2_t(blah value, bool full) : value(value), full(full) {}
};
std::ostream& operator<<(std::ostream& out, blah_manip_2_t in) {
return out << prt(in.value, in.full);
}
blah_manip_2_t full(blah value) {
return blah_manip_2_t(value, true);
}
blah_manip_2_t short(blah value) {
return blah_manip_2_t(value, false);
}
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]