Typically, you do such a thing by striking forward - declaring a template class and a friend function, and then providing specialization in the class definition. However, in this case it is not so simple - the presence of a dependent type puts the Tim class in an undetectable context, so the output will not be executed. However, there is a way:
#include <iostream> #include <type_traits> #include <map> template<class T> struct Bob; template<typename T, typename> bool operator < (const T& a, const T& b); struct DaveTag {}; template<class Tim> struct Bob { struct Dave : DaveTag { Tim t{}; friend bool operator < <Bob<Tim>::Dave, void>(const typename Bob<Tim>::Dave& a, const typename Bob<Tim>::Dave& b); } d; }; template<typename T, typename = typename std::enable_if<std::is_base_of<DaveTag, T>::value>::type> bool operator < (const T& a, const T& b) { return at < bt; } struct X { double t; }; int main() { std::map<Bob<int>::Dave, int> v; v[{}]; // This won't work // X x, y; //bool b = x < y; }
Basically, what I did here allows the compiler to output the full Bob<Tim>::Dave as a template parameter for operator< . However, it is clear that a simple definition would deduce any types for T , which can lead to some difficult to understand problems. To avoid this, I added a small DaveTag tag class that allows you to prevent instances of our most common operator< for anything other than Dave .
Rostislav
source share