Как избежать этого предложения ложного в шаблоне SFINAE?

Поэтому я хочу написать автоматический!=:

template<typename U, typename T>
bool operator!=(U&& u, T&& t) {
  return !( std::forward<U>(u) == std::forward<T>(t) );
}

но это невежливо1, Вот я и пишу

// T() == U() is valid?
template<typename T, typename U, typename=void>
struct can_equal:std::false_type {};

template<typename T, typename U>
struct can_equal<
   T,
   U,
   typename std::enable_if<
      std::is_convertible<
         decltype( std::declval<T>() == std::declval<U>() ),
         bool
      >::value
   >::type
>: std::true_type {};

который является классом черт типа, который говорит "являетсяt == u допустимый код, который возвращает тип, преобразуемый вbool».

Так что я улучшаю!=:

template<typename U, typename T,
  typename=typename std::enable_if<can_equal<T,U>::value>::type
>
bool operator!=(U&& u, T&& t) {
  return !( std::forward<U>(u) == std::forward<T>(t) );
}

и теперь это только допустимое переопределение, если== существует. К сожалению, это немного жадный

struct test {
};
bool operator==(const test&, const test&);
bool operator!=(const test&, const test&);

как это будет в значительной степени каждыйtest() != test() а не выше!= будучи призванным Я думаю, что это не желательно - я бы скорее назвал явное!= чем автоматическая пересылка в== и отрицать.

Итак, я пишу этот класс черт:

template<typename T, typename U,typename=void>
struct can_not_equal // ... basically the same as can_equal, omitted

какие тесты, еслиT != U действует.

Затем мы увеличиваем!= следующее:

template<typename U, typename T,
  typename=typename std::enable_if<
    can_equal<T,U>::value
    && !can_not_equal<T,U>::value
  >::type
>
bool operator!=(U&& u, T&& t) {
  return !( std::forward<U>(u) == std::forward<T>(t) );
}

который, если разобрать его, говорит: «это предложение ложно» -operator!= существует междуT а такжеU тогда и только тогдаoperator!= не существует междуT а такжеU.

Неудивительно, что каждый компилятор, который я тестировал segfaults, когда его кормил. (clang 3.2, gcc 4.8 4.7.2 intel 13.0.1).Я подозреваю, что то, что я делаю, является незаконным, но я хотел бы видеть стандартную ссылку. (редактировать: то, что я делаю, является незаконным, потому что оно вызывает неограниченное рекурсивное расширение шаблона, как определение того,!= применяется требует, чтобы мы проверили, если мой!= применяется. Версия, указанная в комментариях, с#if 1даёт ощутимую ошибку).

Но мой вопрос: есть ли способ убедить мое переопределение, основанное на SFINAE, игнорировать «себя» при принятии решения, потерпеть неудачу или нет, или каким-то образом избавиться от проблемы со ссылками на себя? Или понизьте приоритет моегоoperator!= достаточно низко, поэтому любой явный!= выигрывает, даже если это не так хорошо сочетается?

Тот, который не проверяет "!= «не существует» работает достаточно хорошо, но недостаточно хорошо для меня, чтобы быть настолько невежливым, чтобы внедрить его в глобальное пространство имен.

Цель - любой код, который компилируется без моей "магии"!= делает то же самое, когда моя "магия"!= вводится. Если и только если!= в противном случае является недействительныма также bool r = !(a==b) хорошо сформирован, если моя "магия"!= ворваться.

$43но это невежливо44$template<typename U, typename T> bool operator!=(U&& u, T&& t)SFINAE подумает, что каждая пара типов имеет действительный!= между ними. Затем, когда вы пытаетесь на самом деле позвонить!=, он создается и не компилируется. Кроме того, вы топаете поbool operator!=( const foo&, const foo& ) функции, потому что вы лучше подходите дляfoo() != foo() а такжеfoo a, b; a != b;, Я считаю, что делать оба этих невежливых.

Ответы на вопрос(1)

Ваш ответ на вопрос