The problem
Given the following piece of code :
template <typename T>
struct dummy {
  enum enumenum { a = 1, b = 2, c = 4 };
};
int main() { 
    // I want this line to expands as : 
    // dummy<double>::enumenum a = operator~(dummy<double>::a);
    auto a = ~dummy<double>::a;
}
How do you overload operators on enumenum ?
I'm using std C++14.
What I tried
A naive implementation:
template <typename T>
typename dummy<T>::enumenum 
operator~(typename dummy<T>::enumenum a) {
  return static_cast<typename dummy<T>::enumenum>(operator~(a));
}
Unfortunately the line in question expands as:
int a = ~static_cast<int>(dummy<double>::a);
Which means that the operator was not used (this is the default behavior).
Is it because ADL could not find the right operator~() in the struct namespace (is that even a thing ?) ?
Then I tried: (note the friend)
template <typename T>
struct dummy {
  enum enumenum { a, b, c };
  
  friend enumenum operator~(enumenum a) { 
    return static_cast<enumenum>(~a);
  }
};
This actually works and expands as:
template <>
struct dummy<double> {
  enum enumenum {
    a = static_cast<unsigned int>(1),
    b = static_cast<unsigned int>(2),
    c = static_cast<unsigned int>(4)
  };
  friend inline dummy<double>::enumenum operator~(dummy<double>::enumenum a) {
    return static_cast<dummy<double>::enumenum>(operator~(a));
  }
};
int main()
{
  dummy<double>::enumenum a = operator~(dummy<double>::a);
}
This is the behavior I want. Except, what if I don't want to define the operator in the class body.
So I tried :
template <typename T>
struct dummy {
  enum enumenum { a = 1, b = 2, c = 4 };
  
  // if inline : inline function 'operator~' is not defined [-Wundefined-inline]
  // and adding inline to the template below does not help
  friend enumenum operator~(enumenum a);
};
template <typename T>
typename dummy<T>::enumenum 
operator~(typename dummy<T>::enumenum a) {
  return static_cast<typename dummy<T>::enumenum>(~a);
}
int main() { 
    auto a = ~dummy<double>::a; 
}
The code above expands as:
template<>
struct dummy<double>
{
  enum enumenum
  {
    a = static_cast<unsigned int>(1), 
    b = static_cast<unsigned int>(2), 
    c = static_cast<unsigned int>(4)
  };
  
  friend dummy<double>::enumenum operator~(dummy<double>::enumenum a);
};
int main()
{
  dummy<double>::enumenum a = operator~(dummy<double>::a);
}
This compiles, but does not link! Edit: I believe it does not link because the template is not instantiated thus failing at link time (similarly to the naive implementation above).
Conclusion
Even though I somehow found a way to achieve what I wanted, what if I don't want to define the operator inside the class definition.
Thanks in advance.
 
    