• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Прозрачный тип данных

  • Автор темы kirrun
  • Дата начала
K

kirrun

Идея такая - создать типа данных, полностью поторяющий встроенный, за исключением парочки операторов. Т.е., фактически, в идеале, просто перегрузить несколько операторов встроенных типов.
Но, поскольку это не получится, то хочется просто создать свой тип, так сказать. инкапсулирующий встроенный. Проблема в том, что хочется сделать его абсолютно прозрачным. И вот какая возникает проблема:
объявлен оператор приведения к инкапслируемому типу, объявлен оператор сравнения с себеподобным. В этой ситуации компилятор не может определить, что делать - использовать написанный мной опертор сравнения, или привести к стандартному типу и использовать встроенный оператор сравнения. Здесь хотелось бы сказать ему, что не надо использовтаь строенный оператор...

Ничего дельного в голову не приходит, мб кто-то уже сталкивался, подскажите, пожалуйста...
 
E

European

Приведи код, а то ничего не понятно
 
K

kirrun

окей. Объясняю на том, что реально есть.

ЦЕЛЬ: Нужно сделать так, чтобы типы с плавающей точкой сравнивались с определенной точностью.

Решение - напистаь свой собственный тип.
Код:
class CORE_API FireFloat
Хочется, чтобы он был абсолютно прозрачным. Для этого у него есть конструктор
Код:
	FireFloat()
{
val = 0;
}
FireFloat(const FLOAT_TYPE &v)
{
val = v;
}
FireFloat(const FireFloat &v)
{
val = v.val;
}
и оператор приведения
Код:
	operator FLOAT_TYPE() const
{
return val;
}
Есть, непосредственно, оператор сравнения (он пока сравнивает не учитвая точность - не суть)
Код:
	bool operator<(const FireFloat &v) const
{
return val<v.val;
}

При попытке его использования вылетает ошибка
Код:
X<4;
error C2666: 'core::FireFloat::eek:perator <' : 2 overloads have similar conversions
1> firefloat.h(84): could be 'bool core::FireFloat::eek:perator <(const core::FireFloat &) const'
1> or 'built-in C++ operator<(float, int)'
1> while trying to match the argument list '(Ffloat, int)'

Собственно, в чем она заключается понятно. Интересует как решить эту проблему. Понятное решение - убить опертор приведения. Но тогда тип станет непрозрачным и неудобным для использования...

Я вот и пишу сюда в ндежде, что кто-то уже сталкивался с подобным, и нашел какое-нибудь решение...
 
K

kirrun

омг... Да что ж вы все такие одинаковые?
Не помогает это. Если вдуматься в ошибку, конструктор там вообще ни при чем.

Решение, кажется, нашлось. Сегодня дотестим и выложу.
 
G

grigsoft

Помочь-то explicit поможет, только результат действительно будет не тот что надо.

Я б сказал что проще всего поставить explict конструктору и добавить явные операторы сравнения для числовых типов, вызывающие общую базу. Впрочем, тогда и explicit не нужен :blink:

Собственно, чего я туплю:
Код:
bool operator<(const FireFloat& a, const FLOAT_TYPE &v)
{
cout << "in smart<" << endl;
return a.val<v;
}
template<class TYPE>
bool operator<(const FireFloat& a, const TYPE& b)
{
return a<(FLOAT_TYPE)b;
};
 
K

kirrun

Да, собственно, почти такое решение я и нашел... вечером выложу подробнее код, чтобы закрыть тему.

Сообразил, что не обязательно ждать пока приду домой и забрал код из репозитория.
Вот, вроде бы, так работает.

Дефайны в начале
Код:
#define FLOAT_TYPE float
#define FLOAT_PRECISION 0.000002

Объявление
Код:
class CORE_API FireFloat
{
public:

Три конструктора: пустой, копирования, и от любого типа. Минус этого в том, что в конструкторе имеется приведение к нужному типу, потому умрут все варнинги, связанные с некорректным присвоением (типа Truncation from double to float).
Код:
	FireFloat()
{
val = 0;
}
template<class T>
FireFloat(const T &v)
{
val = (FLOAT_TYPE)v;
}
FireFloat(const FireFloat &v)
{
val = v.val;
}

оператор приведения
Код:
	operator FIRE_INLINE FLOAT_TYPE() const
{
return val;
}

все обычные операторы
Код:
	FireFloat& operator++()
{
val++;
return *this;
}
FireFloat operator++(int)
{
return val++;
}
FireFloat& operator--()
{
val--;
return *this;
}
FireFloat operator--(int)
{
return val--;
}

template<class T>
FireFloat& operator+=(const T &v)
{
val += v;
return *this;
}
template<class T>
FireFloat& operator-=(const T &v)
{
val -= v;
return *this;
}
template<class T>
FireFloat& operator*=(const T &v)
{
val *= v;
return *this;
}
template<class T>
FireFloat& operator/=(const T &v)
{
val /= v;
return *this;
}

template<class T>
FireFloat operator+(const T &v) const
{
return val+v;
}
template<class T>
FireFloat operator-(const T &v) const
{
return val-v;
}
template<class T>
FireFloat operator*(const T &v) const
{
return val*v;
}
template<class T>
FireFloat operator/(const T &v) const
{
return val/v;
}

Пропатченные операторы сравнения
Код:
	template<class T>
bool FIRE_INLINE operator==(const T &v) const
{
return (val-v<=FLOAT_PRECISION && val-v>=-FLOAT_PRECISION);
}
template<class T>
bool FIRE_INLINE operator!=(const T &v) const
{
return !(this->operator== <T>(v));
}
template<class T>
bool FIRE_INLINE operator<(const T &v) const
{
return (v-val>FLOAT_PRECISION);
}
template<class T>
bool FIRE_INLINE operator>(const T &v) const
{
return !(this->operator< <T>(v) || this->operator==<T>(v));
}
template<class T>
bool FIRE_INLINE operator<=(const T &v) const
{
return (this->operator< <T>(v) || this->operator==<T>(v));
}
template<class T>
bool FIRE_INLINE operator>=(const T &v) const
{
return !(this->operator< <T>(v));
}

Поле
Код:
private:
FLOAT_TYPE val;
};

Собственно, был замечен только один минус этого решения, и с ним мы смогли смириться.
Вылетел объявленный для другого типа (вектора) operator*(Ffloat, Vector) - скалярное умножение константы на вектор. Произошло это по очень простой причине. Пока Ffloat был всего лишь тайпдефом встроенного флота, строчка типа
Код:
11*(Vector)a
выполнялась очень просто - 11 приводилось к float'у и вызывался оператор вектора. А теперь 11 приводится к FireFloat'у и, соответсвенно, вызвается его оператор умножения, возвращающий не Vector, как было раньше, а FireFloat.

Вот. А, в целом, прозрачный тип неплохо удался, и пока нас всех устраивает.

Всем спасибо за попытки помочь и особенно grigsoft'у за его решение, совпавшее с моим :rolleyes:

PS. Пусть вас не смущает слово FIRE, так часто встречающееся - это название нашего проекта. Я просто целиком копипастил код, ибо лень править :)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!