Russian Qt Forum
Ноябрь 23, 2024, 04:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: SFINAE Способ определения наличия оператора у класса  (Прочитано 4185 раз)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« : Апрель 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
Записан

Гугль в помощь
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #1 : Апрель 03, 2015, 15:46 »

Вот мой вариант:
http://rextester.com/WYAQ45377
 Улыбающийся

Чуть подправил: http://rextester.com/BCLCC21973
« Последнее редактирование: Апрель 03, 2015, 16:09 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #2 : Апрель 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 )
« Последнее редактирование: Апрель 03, 2015, 17:16 от navrocky » Записан

Гугль в помощь
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #3 : Апрель 03, 2015, 17:13 »

И ещё..
Я бы не привязывался к сравнению размеров, т.е.:
Код
C++ (Qt)
enum { value = (sizeof(*(T*)(0) == *(T*)(0)) != sizeof(no)) };
 

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

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

   Грустный
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #4 : Апрель 03, 2015, 17:25 »

И ещё..
Я бы не привязывался к сравнению размеров, т.е.:
Согласен

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

   Грустный

Исправил.

Спасибо
Записан

Гугль в помощь
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #5 : Апрель 03, 2015, 19:01 »

Да, и ещё одно маленькое замечание: Наверное лучше использовать std::declval вместо конструкции типа:
Код
C++ (Qt)
*static_cast<T*>(0) == *static_cast<T*>(0)
 


http://rextester.com/FTVPW47047
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.174 секунд. Запросов: 20.