如何在 C++98 中实现作用域枚举并且可以像 C++11 中的枚举 class 一样使用?
How to implement scoped enum in C++98 and can be used like enum class in C++11?
在 C++11 中,我们有作用域枚举,我们可以按如下方式使用它。
#include <iostream>
enum class Color
{
RED,
BLUE,
};
int main()
{
Color color = Color::RED;
if (color == Color::RED)
{
std::cout << "red" << std::endl;
}
return 0;
}
我已经在我的项目中到处使用范围枚举。
现在我必须转移到 C++98,所以作用域枚举不能再使用了。
如何在 C++98 中实现作用域枚举并像在 C++11 中一样使用?
如果实现技术比较复杂,能否提取到模板中?
跟随link已经讲了一些技术,但不像C++11那么简单。
How to use enums in C++
例如:
namespace Color
{
enum MyColor
{
RED,
BLUE,
};
}
感谢您的宝贵时间。
在 C++11 之前模拟作用域枚举的常用方法是在 class 声明中声明非作用域枚举:
#include <iostream>
struct Color {
enum MyColor {
kRed,
kBlue
};
};
int main() {
const Color::MyColor color = Color::kRed;
if (color == Color::kRed)
{
std::cout << "red" << std::endl;
}
}
或者,作为一个微小的变化,为了简洁起见可能会造成一些混淆(即在使用地点:"how does MyColor
and Color
relate?"):
#include <iostream>
struct Color {
enum MyColorImpl {
kRed,
kBlue
};
};
typedef Color::MyColorImpl MyColor;
int main() {
const MyColor color = Color::kRed;
if (color == Color::kRed)
{
std::cout << "red" << std::endl;
}
}
当然,您也可以使用问题中显示的名称空间范围界定方法,但它会带来潜在的问题,名称空间可能会扩展到代码库中的其他地方,这反过来可能会导致意外 (开发者期望) 行为;您模拟的作用域枚举可以是例如开始表现为几个不同的非作用域枚举的串联。
#include <iostream>
namespace color {
enum MyColor {
kRed,
kBlue
};
}
namespace color {
enum CarColor {
kAbsolutelyNotRed
};
}
int main() {
const color::MyColor color = color::kRed;
// At best, a -Wenum-compare warning.
if (color == color::kAbsolutelyNotRed)
{
// At worst, a critical logical fault.
std::cout << "absolutely not red (ups, actually red)" << std::endl;
}
}
由于drfi已经给出了详细的解释,我这里还是给出另外一个角度来解决问题。
我们可以使用class来实现枚举,并支持严格的类型检查。
代码修改自 class Month
书中的示例 Effective C++ 3rd: Item 18
#include <iostream>
class Color
{
public:
static Color RED()
{
return Color(0);
}
static Color BLUE()
{
return Color(1);
}
bool operator==(const Color &rhs) const
{
return this->value == rhs.value;
}
bool operator!=(const Color &rhs) const
{
return !(*this == rhs);
}
private:
explicit Color(int value_) : value(value_) {}
int value;
};
int main()
{
Color color = Color::RED();
if (color == Color::RED())
{
std::cout << "red" << std::endl;
}
return 0;
}
在 C++11 中,我们有作用域枚举,我们可以按如下方式使用它。
#include <iostream>
enum class Color
{
RED,
BLUE,
};
int main()
{
Color color = Color::RED;
if (color == Color::RED)
{
std::cout << "red" << std::endl;
}
return 0;
}
我已经在我的项目中到处使用范围枚举。
现在我必须转移到 C++98,所以作用域枚举不能再使用了。
如何在 C++98 中实现作用域枚举并像在 C++11 中一样使用?
如果实现技术比较复杂,能否提取到模板中?
跟随link已经讲了一些技术,但不像C++11那么简单。
How to use enums in C++
例如:
namespace Color
{
enum MyColor
{
RED,
BLUE,
};
}
感谢您的宝贵时间。
在 C++11 之前模拟作用域枚举的常用方法是在 class 声明中声明非作用域枚举:
#include <iostream>
struct Color {
enum MyColor {
kRed,
kBlue
};
};
int main() {
const Color::MyColor color = Color::kRed;
if (color == Color::kRed)
{
std::cout << "red" << std::endl;
}
}
或者,作为一个微小的变化,为了简洁起见可能会造成一些混淆(即在使用地点:"how does MyColor
and Color
relate?"):
#include <iostream>
struct Color {
enum MyColorImpl {
kRed,
kBlue
};
};
typedef Color::MyColorImpl MyColor;
int main() {
const MyColor color = Color::kRed;
if (color == Color::kRed)
{
std::cout << "red" << std::endl;
}
}
当然,您也可以使用问题中显示的名称空间范围界定方法,但它会带来潜在的问题,名称空间可能会扩展到代码库中的其他地方,这反过来可能会导致意外 (开发者期望) 行为;您模拟的作用域枚举可以是例如开始表现为几个不同的非作用域枚举的串联。
#include <iostream>
namespace color {
enum MyColor {
kRed,
kBlue
};
}
namespace color {
enum CarColor {
kAbsolutelyNotRed
};
}
int main() {
const color::MyColor color = color::kRed;
// At best, a -Wenum-compare warning.
if (color == color::kAbsolutelyNotRed)
{
// At worst, a critical logical fault.
std::cout << "absolutely not red (ups, actually red)" << std::endl;
}
}
由于drfi已经给出了详细的解释,我这里还是给出另外一个角度来解决问题。
我们可以使用class来实现枚举,并支持严格的类型检查。
代码修改自 class Month
书中的示例 Effective C++ 3rd: Item 18
#include <iostream>
class Color
{
public:
static Color RED()
{
return Color(0);
}
static Color BLUE()
{
return Color(1);
}
bool operator==(const Color &rhs) const
{
return this->value == rhs.value;
}
bool operator!=(const Color &rhs) const
{
return !(*this == rhs);
}
private:
explicit Color(int value_) : value(value_) {}
int value;
};
int main()
{
Color color = Color::RED();
if (color == Color::RED())
{
std::cout << "red" << std::endl;
}
return 0;
}