#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;
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnN0cnVjdCBDbGFzcyB7CglDbGFzcyhUIGNvbnN0ICZ0KSB7IH0KfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUX0xocywgdHlwZW5hbWUgVF9SaHM+CnN0cnVjdCBDbGFzc0FuZCB7CglDbGFzc0FuZChUX0xocyBjb25zdCAmbGhzLCBUX1JocyBjb25zdCAmcmhzKSB7IH0KfTsKCi8vIEFkZGl0aW9uIG9mIENsYXNzTm90IGFuZCB0aGUgYXBwcm9wcmlhdGUgb3BlcmF0b3JzIGNhdXNlcyBhbiBhbWJpZ3VpdHkgaW4gb3BlcmF0b3ImLgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IENsYXNzTm90IHsKCUNsYXNzTm90KFQgY29uc3QgJnQpIDogdmFsdWUodCkgeyB9CglUIHZhbHVlOwp9OwoKdGVtcGxhdGUgPGNsYXNzIFQ+CnN0cnVjdCBJc0NsYXNzTm90IDogc3RkOjpmYWxzZV90eXBlCnt9OwoKdGVtcGxhdGUgPGNsYXNzIFQ+CnN0cnVjdCBJc0NsYXNzTm90PENsYXNzTm90PFQ+PiA6IHN0ZDo6dHJ1ZV90eXBlCnt9OwoKCnRlbXBsYXRlIDx0eXBlbmFtZSBUX0xocywgdHlwZW5hbWUgVF9SaHM+CnN0cnVjdCBDbGFzc0FuZE5vdCB7CglDbGFzc0FuZE5vdChUX0xocyBjb25zdCAmbGhzLCBUX1JocyBjb25zdCAmcmhzKSB7IH0KfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUX0xocywgdHlwZW5hbWUgVF9SaHM+CkNsYXNzQW5kTm90PFRfTGhzLCBUX1Jocz4gb3BlcmF0b3ImKFRfTGhzIGNvbnN0ICZsaHMsIENsYXNzTm90PFRfUmhzPiBjb25zdCAmcmhzKSB7CglyZXR1cm4gQ2xhc3NBbmROb3Q8VF9MaHMsIFRfUmhzPihsaHMsIHJocy52YWx1ZSk7Cn0KCnRlbXBsYXRlIDx0eXBlbmFtZSBUX1Jocz4KQ2xhc3NOb3Q8VF9SaHM+IG9wZXJhdG9yIShUX1JocyBjb25zdCAmcmhzKSB7CglyZXR1cm4gQ2xhc3NOb3Q8VF9SaHM+KHJocyk7Cn0KCgoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFRfUmhzPgp0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjwhSXNDbGFzc05vdDxUX1Jocz46OnZhbHVlLApDbGFzc0FuZDxDbGFzczxUPiwgVF9SaHM+Pjo6dHlwZSBvcGVyYXRvciYoQ2xhc3M8VD4gY29uc3QgJmxocywgVF9SaHMgY29uc3QgJnJocykgewoJcmV0dXJuIENsYXNzQW5kPENsYXNzPFQ+LCBUX1Jocz4obGhzLCByaHMpOwp9Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVDAsIHR5cGVuYW1lIFQxLCB0eXBlbmFtZSBUX1Jocz4KdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IUlzQ2xhc3NOb3Q8VF9SaHM+Ojp2YWx1ZSwKQ2xhc3NBbmQ8Q2xhc3NBbmQ8VDAsIFQxPiwgVF9SaHM+Pjo6dHlwZSBvcGVyYXRvciYoQ2xhc3NBbmQ8VDAsIFQxPiBjb25zdCAmbGhzLCBUX1JocyBjb25zdCAmcmhzKSB7CglyZXR1cm4gQ2xhc3NBbmQ8Q2xhc3NBbmQ8VDAsIFQxPiwgVF9SaHM+KGxocywgcmhzKTsKfQoKLy8gU2FtcGxlIHVzYWdlLgppbnQgbWFpbigpIHsKCUNsYXNzPGludD4gYSg0Mik7CglDbGFzczxkb3VibGU+IGIoMy4xNCk7CglhdXRvIGMgPSBhICYgIWI7Cn0K