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

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

Страниц: [1] 2 3 4   Вниз
  Печать  
Автор Тема: Специализация шаблонного метода  (Прочитано 25646 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« : Февраль 18, 2016, 16:24 »

Всем привет,

вот столкнулся со следующей проблемой: есть шаблон типа

Код:
template <int Size, class Element = double>
class TVector
{
public:
bool operator==(const TVector<Size, Element>) const
{
// тут происходит "тупое" сравнение элементов через ==
}
}

Естественно, для даблов сравнение будет работать неправильно.
Поэтому появилось желание специализироваться, добавив:

Код:
template <int Size, class Element = double>
class TVector
{
public:
bool operator==(const TVector<Size, double>) const
{
// а тут по умному, через qFuzzyCompare ;)
}

bool operator==(const TVector<Size, Element>) const
{
//...
}
}

Но... не компилируется, студия говорит, что "определение уже существует".
Подозреваю, что тупой компилятор воспринимает Element по умолчанию как double и генерирует 2 идентичных определения оператора (но с разным телом).

Есть ли простые методы борьбы с подобным? Менять сигнатуру шаблона "низя"...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #1 : Февраль 18, 2016, 17:07 »

Лучше вынести операторы сравнения (и вообще подобные бинарные операторы) из класса:

Код
C++ (Qt)
template <size_t Size, class Element = double>
class TVector
{
public:
 
};
 
 
template <size_t Size, class T>
inline bool operator==(const TVector<Size, T> & x, const TVector<Size, T> & y)
{
...
}
 
template <size_t Size>
inline bool operator==(const TVector<Size, double> & x, const TVector<Size, double> & y)
{
...
}
 
 
« Последнее редактирование: Февраль 18, 2016, 17:14 от m_ax » Записан

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

Arch Linux Plasma 5
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #2 : Февраль 18, 2016, 18:15 »

Я где-то слышал звон, что VC не поддерживает специализацию шаблонов для членов класса.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #3 : Февраль 18, 2016, 18:59 »

m_ax, спасибо за идею, но во втором случае ругается на несоответствие количества параметров в сигнатуре шаблона Грустный

Alex Custov, да не, поддерживать то поддерживает, другой вопрос - КАК...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #4 : Февраль 18, 2016, 20:32 »

Цитировать
спасибо за идею, но во втором случае ругается на несоответствие количества параметров в сигнатуре шаблона
В смысле не совместимость? А что именно пишет?

У меня всё работает..
Записан

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

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Февраль 19, 2016, 07:47 »

Код
C++ (Qt)
#include <type_traits>
 
template <int Size, class Element = double>
class TVector
{
public:
bool operator==(const TVector<Size, Element> & sec) const
{
if (std::is_floating_point<Element>::value)
return true;
else
return false;
}
};
 
Ну или через typeid для старых компиляторов. И вообще, не лучше ли так

Код
C++ (Qt)
#include <type_traits>
 
template <int Size, class Element = double>
class TVector
{
public:
       template <class T>
bool operator==(const T & sec) const
      {
         if (this->size() != sec.size()) return false;
         ...
      }
 
 
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #6 : Февраль 19, 2016, 08:05 »

Ну или через typeid для старых компиляторов.
Шаблоны как раз и призваны избавить нас от таких проверок в рантайме.

И вообще, не лучше ли так
Как? Вначале проверять размер? Улыбающийся
Так ТС его скорее всего проверяет. У него проблема в другом.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Февраль 19, 2016, 09:01 »

Шаблоны как раз и призваны избавить нас от таких проверок в рантайме.
А что "такого уж хорошего" в этом избавлении? Расписывать длинные сопли с угребочными именами x и у? Да за одно это уже надо ставить к стенке.

Как? Вначале проверять размер? Улыбающийся
Так ТС его скорее всего проверяет. У него проблема в другом.
Темплейтщина на каждый чих создает новый класс - и это далеко не всегда удобно/выгодно. Чего это я не могу сравнить вектор int c вектором float? Или с вектором std? Такая операция совершенно разумна.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Февраль 19, 2016, 09:18 »

А что "такого уж хорошего" в этом избавлении?
То что не нужно тратить время при исполнении на проверки, которые можно выполнить в компилетайме.
Для вас это не важно, но бывают программы не только для секретарш. Подмигивающий

Расписывать длинные сопли с угребочными именами x и у? Да за одно это уже надо ставить к стенке.
Чего? Улыбающийся
« Последнее редактирование: Февраль 19, 2016, 09:22 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Февраль 19, 2016, 10:17 »

То что не нужно тратить время при исполнении на проверки, которые можно выполнить в компилетайме.
Ага, ага. "И чтобы ловить ошибки на этапе компиляции". Эта мысль (сама по себе разумная) особенно часто доводится до полного абсурда. Цель достигается слишком дорогой ценой - раздутием кода на ровном месте. А получившаяся конструкция оказывается негибкой, и при малейшем изменении опять надо чего-то "параметризовать". А раздумья над ошибками компиляции нередко превышают затраты на поиск в runtime

...но бывают программы не только для секретарш. Подмигивающий
Может и бывают - но Вы уж точно не их автор  Улыбающийся
Записан
kramer
Гость
« Ответ #10 : Февраль 19, 2016, 10:17 »

Есть ли простые методы борьбы с подобным? Менять сигнатуру шаблона "низя"...
Простых, наверное, нет. С++ не поддерживает частичную специализацию шаблонных функций. Так что вариантов несколько:
1. Частично специализировать весь класс целиком
2. Сделать сам оператор шаблонным и полностью специализировать его для float и double и всех возможных значений Size (я полагаю, их немного)
3. Вынести сравнение в отдельный класс-стратегию, и вызывать метод этого класса из оператора. Для выбора стратегии по умолчанию можно использовать std::conditional<std::is_floating_point<...>::value...>
4. Просто поставить условие, как указал Igors. Компилятор уберет ненужную ветку из соответствующей интстанциации как dead code.
5. Еще можно заморочиться со SFINAE и как-то сделать так, чтобы инстанциировалась только одна перегрузка для operator== в зависимости от типа элемента.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #11 : Февраль 19, 2016, 10:22 »

Код
C++ (Qt)
if (std::is_floating_point<Element>::value)
return true;
else
return false;
 

Код
C++ (Qt)
return std::is_floating_point<Element>::value;
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Февраль 19, 2016, 10:29 »

Ага, ага. "И чтобы ловить ошибки на этапе компиляции". Эта мысль (сама по себе разумная) особенно часто доводится до полного абсурда. Цель достигается слишком дорогой ценой - раздутием кода на ровном месте. А получившаяся конструкция оказывается негибкой, и при малейшем изменении опять надо чего-то "параметризовать". А раздумья над ошибками компиляции нередко превышают затраты на поиск в runtime
Это потому что вы не знаете инструмент, которым пытаетесь пользоваться.

Может и бывают - но Вы уж точно не их автор  Улыбающийся
Так я хотя бы стремлюсь... А вы гомнокодите, знаете это и пытаетесь просто придумать красивую отмазку. Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #13 : Февраль 19, 2016, 10:30 »

Код
C++ (Qt)
template <int Size, class Element = double>
class TVector
{
public:
bool operator==(const TVector<Size, Element> & sec) const
{
if (std::is_floating_point<Element>::value)
return true;
else
return false;
}
};
 
Вообще это самая плохая идея.. Она не гибкая, не компил тайм и самое главное, если пользователь захочет использовать свой тип с нетривиальным сравнением, то ему либо придётся запускать свои ручёнки в кишки TVector и писать очередной if else, либо определять свой специализированный оператор сравнения, как я в начале и предлагал.  
Записан

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

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Февраль 19, 2016, 11:55 »

Вообще это самая плохая идея.. Она не гибкая, не компил тайм и самое главное, если пользователь захочет использовать свой тип с нетривиальным сравнением, то ему либо придётся запускать свои ручёнки в кишки TVector и писать очередной if else,
И что? Это дешево, удобно, практично. Нет никаких оснований отказываться от простого кода. Гляньте как в Qt сделано сравнение QVariant   

либо определять свой специализированный оператор сравнения, как я в начале и предлагал.   
А так значит "рученки не запускаются"? Вынесли из класса - и якобы это уже "гибкость"? Будет double вместо float или наоборот - и вот уже надо рисовать очередной оператор. "Зато" легко можно не увидеть какого-то внешнего.

Хорошо, гибкость так гибкость. Надеюсь Racheengel позволит мне чуть "копнуть". Вот те же флоты потребовалось сравнивать с другими типами (хоть int), и по-разному, напр "точное сравнение", "fuzzy" и с каким-то фиксированным "epsilon". У меня проблем нет - да, подрисовал if/else, добавил GetCompareMode и SetCompareMode - готовченко!

А вот что Вы будете делать с тучей операторов? Как обычно ("Вы изменили задачу!", "так Вы определитесь", "пересмотреть архитектуру приложения" и.т.п.)? Или я ошибаюсь?  Улыбающийся
Записан
Страниц: [1] 2 3 4   Вверх
  Печать  
 
Перейти в:  


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