#include <type_traits>

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) { }
};

// Addition of ClassNot and the appropriate operators causes an ambiguity in operator&.
template <typename T>
struct ClassNot {
	ClassNot(T const &t) : value(t) { }
	T value;
};

template <class T>
struct IsClassNot : std::false_type
{};

template <class T>
struct IsClassNot<ClassNot<T>> : std::true_type
{};


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_Rhs> operator!(T_Rhs const &rhs) {
	return ClassNot<T_Rhs>(rhs);
}



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);
}

template <typename T0, typename T1, typename T_Rhs>
typename std::enable_if<!IsClassNot<T_Rhs>::value,
ClassAnd<ClassAnd<T0, T1>, T_Rhs>>::type operator&(ClassAnd<T0, T1> const &lhs, T_Rhs const &rhs) {
	return ClassAnd<ClassAnd<T0, T1>, T_Rhs>(lhs, rhs);
}

// Sample usage.
int main() {
	Class<int> a(42);
	Class<double> b(3.14);
	auto c = a & !b;
}
