如果您按照您建议的方式使用 C++11 enum class,包括命名空间,您确实需要两个限定符来访问它们:Colour::Colour::RED,您可能会觉得这很烦人。
但是,我认为将 from_string 和 to_string 函数放入命名空间中没有用处——无论是出于类型安全还是出于任何其他原因。
to_string() 适用于多种类型,而不仅仅是Colour。事实上,从C++11开始,甚至还有std::to_string,你可以将它应用到各种内置类型上,将它们转换成std::string。简单地扩展该概念以涵盖用户定义的类型是有意义的:
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";
}
}
然后您可以使用to_string(42) 和to_string(Color::red),这是完全类型安全的(与任何函数重载/模板特化一样类型安全)。
同样适用于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");
}
我只提供了Color 的实现,但是为其他类型添加它会很简单。
使用 this 是类型安全的,并且仅在必要时需要明确指定 Color(作为模板参数或范围限定符),无需重复:
int main()
{
Color c = Color::red;
std::cout << to_string(c) << std::endl;
c = from_string<Color>("red");
return 0;
}
(如果你害怕名字冲突,或者一般不想把任何东西放在全局范围内,你可以把 to_string 和 from_string 放到命名空间 convert 中,并将它们用作 convert::from_string<Color>("red") 等. 甚至,创建一个类模板convert,这样您就可以将其命名为convert<Color>::from_string("red"),从而生成非常易于准备、直观的代码。)