1

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.

Chris Johnson
  • 10,469
  • 4
  • 31
  • 35
  • would listing `KeyEvent::TypeFlags` and `MouseButtonEvent::TypeFlags` be enough, or any `SOME_CLASS::TypeFlags` should be matched ? – Piotr Skotnicki Sep 12 '14 at 10:51
  • @Piotr S. ideally any SOME_CLASS::TypeFlags should be matched. In response to your deleted answer I clarified the question to say that there are rather more than two xxxEvent classes in real codebase. – Chris Johnson Sep 12 '14 at 10:54
  • Anything to the left of `::` is a non-deduced context. The compiler can't deduce `EC` in your templated operator. – T.C. Sep 12 '14 at 11:20
  • There are quite some related questions on SO, e.g. http://stackoverflow.com/q/18803940 – dyp Sep 12 '14 at 17:34

0 Answers0