If you use the C++11 enum class
the way you suggested, including the namespace, indeed you will need two qualifiers to access them: Colour::Colour::RED
, which you may find annoying.
However, I don't think it is useful – neither for type safety nor for any other reason – to put the from_string
and to_string
functions into a namespace.
to_string()
applies to many types, not only Colour
. In fact, since C++11, there is even std::to_string
, which you can apply to various built-in types to transform them into std::string
. It makes sense to simply extend that notion to cover user-defined types:
template <typename T>
std::string to_string(const T arg)
{ return std::to_string(arg); }
template <>
std::string to_string(const Color c)
{
switch (c)
{
case Color::red:
return "red";
case Color::green:
return "green";
case Color::blue:
default:
return "blue";
}
}
You can then use to_string(42)
as well as to_string(Color::red)
, and this is completely type-safe (as type-safe as any function overload / template specialization).
Similarly for from_string
:
template <typename T>
T from_string(const std::string &str);
template <>
Color from_string<Color>(const std::string &str)
{
if (str == "red")
return Color::red;
else if (str == "green")
return Color::green;
else if (str == "blue")
return Color::blue;
else
throw std::invalid_argument("Invalid color");
}
I have provided only the implementation for Color
, but it would be straight-forward to add it for other types.
Using this is type-safe and requires the explicit specification of Color
(as template argument or scope qualifier) only where necessary, without duplication:
int main()
{
Color c = Color::red;
std::cout << to_string(c) << std::endl;
c = from_string<Color>("red");
return 0;
}
(If you are afraid of name-clashes, or generally don't want to put anything in global scope, you can put to_string
and from_string
into a namespace convert
and use them as convert::from_string<Color>("red")
etc. Or even, create a class template convert
such that you can call it as convert<Color>::from_string("red")
, which result in very easy-to-ready, intuitive code.)