Re: How can I alter how a user-defined type/enum is displayed? (facet/locale?)
{mod note: To avoid the funky formatting, set your line limit to wrap at
about 70 characters.}
On Jul 1, 10:02 am, Lorri <steve.lori...@gmail.com> wrote:
Hi folks
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)
C++ allows you to overload on types, and so that's a good place to
start.
Your enum's type doesn't change, but the way you may wish to display
it
does. Therefore I have found useful practice for various objects to
write a thin wrapper class that models the display concept, holding a
reference (or copy in the case of enums) of your underlying data.
Then overload the stream operators for the wrapper class, rendering as
you wish.
You might do something like:
namespace streaming
{
template <typename T> struct NameOf
{
NameOf(T const & obj) : obj_(obj) { }
T const & obj_;
};
template <typename T> NameOf<T> showSameOf(T obj) { return
NameOf<T>(obj); }
template <typename T> struct ShortNameOf
{
NameOf(T const & obj) : obj_(obj) { }
T const & obj_;
};
template <typename T> ShortNameOf<T> showShortNameOf(T obj) { return
ShortNameOf<T>(obj); }
} // streaming
as a generic concept. Then overload a specialization of operator<<
for your
enum. Note, for each way of formatting, you have a simple class
holder and a
helper function to instantiate class template with minimal effort.
The above
classes could be further reduced to a single macro, so when you have
new ideas
for formatting, you just declare another line of the macro:
#define MAKE_FORMATTER(NAME) \
template <typename T> struct NAME \
{ \
NAME(T const & obj) : obj_(obj) { } \
T const & obj_; \
}; \
template <typename T> NAME<T> show##NAME(T obj) \
{ \
return NAME<T>(obj); \
} \
MAKE_FORMATTER(NameOf);
MAKE_FORMATTER(ShortNameOf);
an so on. The above would be generic library code. Below would be
your
enum-specific code. Note, you can use the MAKE_FORMATTER macro in
your
code if you have a formatting concept for your class that's not
generic
(but perhaps could use a similar-but-different macro to generate a
non-
template version.)
// The code defining your enum + associated functions
#include "streaming/nameof.hpp" // includes the above code
#include <iostream>
enum blah { FOO, BAR };
char const * toString(blah b)
{
switch (blahwrapper)
{
case FOO: return "FOO";
case BAR: return "BAR"'
}
return "?";
}
std::ostream & operator<<(std::ostream & os, NameOf<blah> >
blahwrapper)
{
return os << toString(blahwrapper.obj_);
}
std::ostream & operator<<(std::ostream & os, ShortNameOf<blah> >
blahwrapper)
{
return os << toString(blahWrapper.obj_)[0];
}
And so on. Now with that all done, users can use your code easily
enough:
You could even go a step farther and templatize operator<< on
NameOf<T> such
that it always calls toString on whatever T is, and then you only
woudl have
to provide toString and NameOf just works with it.
Finally, user code might look like this:
blah b = FOO;
std::cout << "b as a number: " << b << ", spelled: " <<
streaming::nameOf(b)
<< ", abbreviated: " << streaming::shortNameOf(b) << endl;
Putting it all together:
namespace streaming
{
#define MAKE_FORMATTER(NAME) \
template <typename T> struct NAME \
{ \
NAME(T const & obj) : obj_(obj) { } \
T const & obj_; \
}; \
template <typename T> NAME<T> show##NAME(T obj) \
{ \
return NAME<T>(obj); \
} \
MAKE_FORMATTER(NameOf)
MAKE_FORMATTER(ShortNameOf)
} // streaming
#include <iostream>
enum blah { FOO, BAR };
char const * toString(blah b)
{
switch (b)
{
case FOO: return "FOO";
case BAR: return "BAR";
}
return "?";
}
std::ostream & operator<<(std::ostream & os, streaming::NameOf<blah>
wrap)
{
return os << toString(wrap.obj_);
}
std::ostream & operator<<(std::ostream & os,
streaming::ShortNameOf<blah> wrap)
{
return os << toString(wrap.obj_)[0];
}
// user code
int main()
{
blah b = FOO;
std::cout << "b as a number: " << b
<< ", spelled: " << streaming::showNameOf(b)
<< ", abbreviated: " << streaming::showShortNameOf(b)
<< std::endl;
}
Chris
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]