I'm trying to put some typesafe flags into several related classes (more than just the two I use as examples here), which I am currently doing with an enum TypeFlags in each class. I'd like to define an operator| on each of these enums. I can do this by writing separate operator| function for each of KeyEvent::TypeFlags, MouseEvent::TypeFlags, etc., or, as below, by defining a templated function:
#include <iostream>
class KeyEvent
{
public: enum TypeFlags {KEYFLAG1=1, KEYFLAG2=2, KEYFLAG3=4};
};
class MouseButtonEvent
{
public: enum TypeFlags {MOUSEFLAG1=1, MOUSEFLAG2=2, MOUSEFLAG3=4};
};
template<typename EC> EC operator|(EC a, EC b)
{
return static_cast<EC>(static_cast<int>(a)|static_cast<int>(b));
}
void DoSomething(KeyEvent::TypeFlags t) {std::cout << t << std::endl;}
int main()
{
DoSomething(KeyEvent::KEYFLAG1 | KeyEvent::KEYFLAG2);
return 0;
}
The code above works, but this templated operator| is not ideal because it operates on anything. I would like to restrict it to operating on only the Class::TypeFlags enums. I have tried replacing the template above with:
template<typename EC> typename EC::TypeFlags operator|(typename EC::TypeFlags a, typename EC::TypeFlags b)
{
return static_cast<typename EC::TypeFlags>(static_cast<int>(a)|static_cast<int>(b));
}
but, while this compiles, the new templated operator| is not called [T.C. in the comments has explained why]. (Instead, when the two flags are ORed together, they are implicitly converted to int, and the int version of operator| is called. The resulting int then cannot be passed to DoSomething.)
Is there a way of writing a templated operator| so that it acts on only my TypeFlags enums? If it exists, I'd like a solution which a) doesn't allow mixing of flags between different classes, and b) doesn't need to be modified if I add or remove an Event class with flags in it.