From: Chris Uzdavinis on
{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...(a)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! ]