The enable_if type does not belong to a specific template class

TL; DR: see last paragraph.

I have operator& defined for several template classes, for example:

 template <typename T> struct Class { Class(T const &t) { } }; template <typename T_Lhs, typename T_Rhs> struct ClassAnd { ClassAnd(T_Lhs const &lhs, T_Rhs const &rhs) { } }; template <typename T, typename T_Rhs> ClassAnd<Class<T>, T_Rhs> operator&(Class<T> const &lhs, T_Rhs const &rhs) { return ClassAnd<Class<T>, T_Rhs>(lhs, rhs); } template <typename T0, typename T1, typename T_Rhs> ClassAnd<ClassAnd<T0, T1>, T_Rhs> operator&(ClassAnd<T0, T1> const &lhs, T_Rhs const &rhs) { return ClassAnd<ClassAnd<T0, T1>, T_Rhs>(lhs, rhs); } int main() { Class<int> a(42); Class<double> b(3.14); auto c = a & b; } 

This works great.

The problem occurs when I want to add a not operation, which is only allowed on one or the other side of the operation, and should return an instance of ClassAndNot , not ClassAnd :

 template <typename T> struct ClassNot { ClassNot(T const &t) : value(t) { } T value; }; template <typename T_Lhs, typename T_Rhs> struct ClassAndNot { ClassAndNot(T_Lhs const &lhs, T_Rhs const &rhs) { } }; template <typename T_Lhs, typename T_Rhs> ClassAndNot<T_Lhs, T_Rhs> operator&(T_Lhs const &lhs, ClassNot<T_Rhs> const &rhs) { return ClassAndNot<T_Lhs, T_Rhs>(lhs, rhs.value); } template <typename T_Rhs> ClassNot<T> operator!(T_Rhs const &rhs) { return ClassNot<T_Rhs>(rhs); } ... auto c = a & !b; 

This leads to ambiguity between operator& , which takes an arbitrary right side, to return a ClassAnd , and operator& on the right side of ClassNot to return ClassAndNot .


Question:

How can std::enable_if be used here to disable the first operator& if its right side is of any type of ClassNot ? Is there something like std::is_same that returns true if one side is an instance of the template of the other?

ps You can find a complete working example of ideone .

+5
source share
1 answer

You can create your own trait for yourself:

 template <class T> struct IsClassNot : std::false_type {}; template <class T> struct IsClassNot<ClassNot<T>> : std::true_type {}; template <typename T, typename T_Rhs> typename std::enable_if<!IsClassNot<T_Rhs>::value, ClassAnd<Class<T>, T_Rhs>>::type operator&(Class<T> const &lhs, T_Rhs const &rhs) { return ClassAnd<Class<T>, T_Rhs>(lhs, rhs); } 

Living example


Of course, you can go crazy with generalizations and create a universal trait:

 template <class T, template <class...> class TT> struct is_instantiation_of : std::false_type {}; template <template <class... > class TT, class... A> struct is_instantiation_of<TT<A...>, TT> : std::true_type {}; template <class T> using IsClassNot = is_instantiation_of<T, ClassNot>; 

Living example

+6
source

Source: https://habr.com/ru/post/1202406/


All Articles