Thanks to G. Sliepen, who gave me a lot very meaningful & useful advice on my implementation about overloading bit operators for a special scoped enum.
Now I have modified the code snippet to follow his advice.
For creating generic overloading bitwise functions to manipulate the enum
type, I think my implementation can indeed accomplish this goal (code is seen below).
This and this code review use a somewhat complex way to achieve the said goal, which is still hard for me to read and understand (I will try my best to fully understand them later).
Is there any potential problem with my implementation?
Here is my code:
#include <iostream>
#include <stdint.h>
#include <type_traits>
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T operator|(const T& a, const T& b)
{
using udl_type = typename std::underlying_type<T>::type;
return static_cast<T>(static_cast<udl_type>(a) | static_cast<udl_type>(b));
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T& operator|=(T& a, const T& b)
{
a=(a|b);
return a;
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T operator&(const T& a, const T& b)
{
using udl_type = typename std::underlying_type<T>::type;
return static_cast<T>(static_cast<udl_type>(a) & static_cast<udl_type>(b));
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T operator&=(T& a, const T& b)
{
a = a&b;
return a;
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T operator^(const T& a, const T& b)
{
using udl_type = typename std::underlying_type<T>::type;
return static_cast<T>(static_cast<udl_type>(a) ^ static_cast<udl_type>(b));
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T& operator^=(T& a, const T& b)
{
a = a ^ b;
return a;
}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
T operator~(const T& a)
{
using udl_type = typename std::underlying_type<T>::type;
return static_cast<T>(~static_cast<udl_type>(a));
}
class ModuleSwitch
{
public:
enum class CameraPosition : uint8_t
{
FRONT_CAMERA = 1, //NONE is remove to avoid the user calls enable(ModuleSwitch::NONE);
MIDDLE_CAMERA = 2,
BACK_CAMERA = 4,
};
public:
ModuleSwitch();
void enable(const CameraPosition&);
void disable(const CameraPosition&);
bool is_enabled(const CameraPosition&) const;
private:
CameraPosition m_mod_status;
};
//NONE is remove to avoid the user calls enable(ModuleSwitch::NONE);
//Is there any better to way to init m_mod_status?
ModuleSwitch::ModuleSwitch(): m_mod_status(static_cast<CameraPosition>(0)){};
void ModuleSwitch::enable(const CameraPosition& pos)
{
m_mod_status |= pos;
}
void ModuleSwitch::disable(const CameraPosition& pos)
{
m_mod_status &= ~pos;
}
bool ModuleSwitch::is_enabled(const CameraPosition& pos) const
{
return static_cast<std::underlying_type<CameraPosition>::type>(m_mod_status & pos)!=0;
}
int main() {
ModuleSwitch mod_swt;
using CameraPosition = ModuleSwitch::CameraPosition;
auto print_camera_status = [](const ModuleSwitch& mod_swt){
std::cout << "front camera enabled:" << mod_swt.is_enabled(CameraPosition::FRONT_CAMERA) << std::endl;
std::cout << "middle camera enabled:" << mod_swt.is_enabled(CameraPosition::MIDDLE_CAMERA) << std::endl;;
std::cout << "back camera enabled:" << mod_swt.is_enabled(CameraPosition::BACK_CAMERA) << std::endl;;
};
std::cout <<"#1" << std::endl;
mod_swt.enable(CameraPosition::FRONT_CAMERA);
print_camera_status(mod_swt);
std::cout <<"#2" << std::endl;
mod_swt.enable(CameraPosition::MIDDLE_CAMERA);
print_camera_status(mod_swt);
std::cout <<"#3" << std::endl;
mod_swt.enable(CameraPosition::BACK_CAMERA);
print_camera_status(mod_swt);
std::cout <<"#4" << std::endl;
mod_swt.disable(CameraPosition::FRONT_CAMERA);
print_camera_status(mod_swt);
std::cout <<"#5" << std::endl;
mod_swt.disable(CameraPosition::MIDDLE_CAMERA);
print_camera_status(mod_swt);
std::cout <<"#6" << std::endl;
mod_swt.disable(CameraPosition::BACK_CAMERA);
print_camera_status(mod_swt);
return 0;
}
int
constants asenum
values to be able to use the symbols at compile time. However, in C++ and C23, you can declare the flags asconstexpr unsigned
values. If you intend to use them this way, do you actually want anenum
at all? \$\endgroup\$