Russian Qt Forum

Программирование => С/C++ => Тема начата: navrocky от Апрель 03, 2015, 13:24



Название: SFINAE Способ определения наличия оператора у класса
Отправлено: navrocky от Апрель 03, 2015, 13:24
Перебрал несколько способов на stackoverflow определить наличие оператора "==" у класса при помощи SFINAE. Но они не рабочие.

Первый способ:
Код
C++ (Qt)
#include <memory>
#include <iostream>
using namespace std;
 
template <typename Type>
struct HasEqualOperator
{
   typedef char yes[1];
   typedef char no[2];
 
   template <int N>
   struct SFINAE {};
 
   template <typename T>
   static yes& isEqualComparable(SFINAE<sizeof(*static_cast<T*>(0) == *static_cast<T*>(0))>* = 0);
 
   template <typename T>
   static no& isEqualComparable(...);
 
   enum { value = sizeof(isEqualComparable<Type>(0)) == sizeof(yes) };
};
 
struct NoOperator
{};
 
int main() {
 
typedef std::shared_ptr<int> MyType;
 
cout << HasEqualOperator<MyType>::value << endl;
cout << HasEqualOperator<NoOperator>::value << endl;
 
return 0;
}

Студийный компилятор не определяет отсутствие оператора == у struct NoOperator.

Второй вариант с перегрузкой оператора ==:
Код
C++ (Qt)
#include <memory>
#include <iostream>
using namespace std;
 
namespace OpCheck
{
typedef bool no[2];
template<typename T> static no& operator==(const T&, const T&);
template <typename T>
struct EqualOperatorExists
{
   enum { value = (sizeof(*(T*)(0) == *(T*)(0)) != sizeof(no)) };
};
}
 
int main() {
 
typedef std::shared_ptr<int> MyType;
 
cout << OpCheck::EqualOperatorExists<MyType>::value << endl;
 
return 0;
}

Но он не собирается для shared_ptr на всех компиляторах.

Можно ли как-то починить первый способ или есть лучшее решение?

Буст не предлагать, хотелось бы обойтись только стандартом C++11

Тестить код можно здесь: http://rextester.com/RBJVR88775


Название: Re: SFINAE Способ определения наличия оператора у класса
Отправлено: m_ax от Апрель 03, 2015, 15:46
Вот мой вариант:
http://rextester.com/WYAQ45377 (http://rextester.com/WYAQ45377)
 :)

Чуть подправил: http://rextester.com/BCLCC21973 (http://rextester.com/BCLCC21973)


Название: Re: SFINAE Способ определения наличия оператора у класса
Отправлено: navrocky от Апрель 03, 2015, 17:07
Спасибо, помогло.

И мой второй способ также заработал.

Это:
Код
C++ (Qt)
template<typename T> static no& operator==(const T&, const T&);
заменил на это:
Код
C++ (Qt)
template<typename T, typename R> static no& operator==(const T&, const R&);

Ваш код более красивый, его возьму.

По сути получилось обойтись без SFINAE.

Это я всё свой variant курочу https://github.com/navrocky/Variant )


Название: Re: SFINAE Способ определения наличия оператора у класса
Отправлено: m_ax от Апрель 03, 2015, 17:13
И ещё..
Я бы не привязывался к сравнению размеров, т.е.:
Код
C++ (Qt)
enum { value = (sizeof(*(T*)(0) == *(T*)(0)) != sizeof(no)) };
 

Всё же сравнение по типу более логично в данном случае, имхо.. Но дело, конечно, ваше)

И ещё..
Вы так и не поправили тот потенциальный баг (о котором я уже говорил) в методе
Код
C++ (Qt)
template <typename T>
   bool tryGetValue(T*& val)
 

   :(


Название: Re: SFINAE Способ определения наличия оператора у класса
Отправлено: navrocky от Апрель 03, 2015, 17:25
И ещё..
Я бы не привязывался к сравнению размеров, т.е.:
Согласен

И ещё..
Вы так и не поправили тот потенциальный баг (о котором я уже говорил) в методе
Код
C++ (Qt)
template <typename T>
   bool tryGetValue(T*& val)
 

   :(

Исправил.

Спасибо


Название: Re: SFINAE Способ определения наличия оператора у класса
Отправлено: m_ax от Апрель 03, 2015, 19:01
Да, и ещё одно маленькое замечание: Наверное лучше использовать std::declval вместо конструкции типа:
Код
C++ (Qt)
*static_cast<T*>(0) == *static_cast<T*>(0)
 


http://rextester.com/FTVPW47047
 (http://rextester.com/FTVPW47047)