EqualityComparable объяснение черты - PullRequest
0 голосов
/ 03 июня 2018

Читая главу 22 шаблонов C ++, второе издание, я пытаюсь понять реализацию черты EqualityComparable.Но я не могу понять, как компилятор решил активировать запасной вариант или нет.

В дополнение к этому есть две функции, которые только объявлены, но программа компилируется и запускается.Это странно для меня.

Вот код.Заголовочный файл IsEqualityComparable.hpp

#include <utility>        // for declval()
#include <type_traits>    // for true_type and false_type

template<typename T>
class IsEqualityComparable
{
 private:
 // test convertibility of == and ! == to bool:
 static void* conv(bool);  // to check convertibility to bool
 template<typename U>
 static std::true_type test(decltype(conv(std::declval<U const&>() ==
                                        std::declval<U const&>())),
                          decltype(conv(!(std::declval<U const&>() ==
                                          std::declval<U const&>())))
                         );
// fallback:
template<typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr,
                                             nullptr))::value;
};

Исходным файлом является следующий

#include <iostream>
#include <exception>
#include <utility>
#include <functional>
#include "isequalitycomparable.hpp"

template<typename T,
     bool EqComparable = IsEqualityComparable<T>::value>
struct TryEquals
{
  static bool equals(T const& x1, T const& x2) {
  std:: cout << "IsEqualityComparable equals::"<<std::endl;
  return x1 == x2;
}
};
class NotEqualityComparable : public std::exception
{
};
template<typename T>
struct TryEquals<T, false>
{
  static bool equals(T const& x1, T const& x2) {
  std:: cout << "Throw::"<<std::endl;
  throw NotEqualityComparable();
}
};
void foo(int)
{
} 
void bar(int)
{
}
class A
{
 public:
 A() = default;
 friend bool operator ==(A a1 , A a2)
 {
    return true;
 }
};
int main()
{
 std:: cout << "Enter" << std::endl;
 std::function<void(int)> f = foo;
 std::function<void(int)> f2 = f;
 std:: cout << "Enter" << std::endl;
 //std:: cout << "Check::"<< 
 //TryEquals<std::function<void(int)>>::equals(f,f2) << std::endl;
 A a1;
 A a2;
 std:: cout << "Check::"<< TryEquals<A>::equals(a1,a2) << std::endl;
 return 0;
}

TryEquals<std::function<void(int)>>::equals(f,f2)

вызывает исключение, посколькуоператор == не реализован, но

TryEquals<A>::equals(a1,a2)  

возвращает 1, поскольку в классе A есть оператор ==.

В этом пункте мне нужна помощь, чтобы понять, как conv и test работают.

Кроме того, как работает

static constexpr bool value = decltype(test<T>(nullptr,
                                               nullptr))::value

?

Я перепутал это выражение

decltype(test<T>(nullptr,nullptr))::value. 

1 Ответ

0 голосов
/ 03 июня 2018

Функции не нужно определять, потому что они на самом деле никогда не вызываются.

decltype - это Неоцененный контекст , где он вычисляет возвращаемый тип функции, но никогда не пытается вычислить возвращаемое значение .

В этом случае оно комбинируется с sfinae , так что если decltype не может выяснитьтип возврата == (возможно, потому что оператор не существует), перегрузка test будет игнорироваться.И тогда вместо этого будет выбран test(...).

При этом используется тот факт, что ... является абсолютным худшим соответствием для типа параметра, поэтому он будет использоваться, только если нет других доступных перегрузок (таким образом,«отступление»).

И, кстати, std::declval тоже никогда не определяется.

...