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.