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

Тема в разделе "Общие вопросы по С и С++", создана пользователем kirrun, 25 фев 2008.

  1. kirrun

    kirrun Member

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

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

    Регистрация:
    4 сен 2006
    Сообщения:
    2.580
    Симпатии:
    0
    Приведи код, а то ничего не понятно
     
  3. kirrun

    kirrun Member

    Регистрация:
    8 апр 2007
    Сообщения:
    7
    Симпатии:
    0
    окей. Объясняю на том, что реально есть.

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

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

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

    grigsoft Well-Known Member

    Регистрация:
    15 ноя 2005
    Сообщения:
    735
    Симпатии:
    0
    Сделать конструктор explicit?
     
  5. kirrun

    kirrun Member

    Регистрация:
    8 апр 2007
    Сообщения:
    7
    Симпатии:
    0
    омг... Да что ж вы все такие одинаковые?
    Не помогает это. Если вдуматься в ошибку, конструктор там вообще ни при чем.

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

    grigsoft Well-Known Member

    Регистрация:
    15 ноя 2005
    Сообщения:
    735
    Симпатии:
    0
    Помочь-то explicit поможет, только результат действительно будет не тот что надо.

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

    Собственно, чего я туплю:
    Код (Text):
    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;
    };
     
  7. kirrun

    kirrun Member

    Регистрация:
    8 апр 2007
    Сообщения:
    7
    Симпатии:
    0
    Да, собственно, почти такое решение я и нашел... вечером выложу подробнее код, чтобы закрыть тему.

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

    Дефайны в начале
    Код (Text):
    #define FLOAT_TYPE float
    #define FLOAT_PRECISION 0.000002
    Объявление
    Код (Text):
    class CORE_API FireFloat
    {
    public:
    Три конструктора: пустой, копирования, и от любого типа. Минус этого в том, что в конструкторе имеется приведение к нужному типу, потому умрут все варнинги, связанные с некорректным присвоением (типа Truncation from double to float).
    Код (Text):
        FireFloat()
    {
    val = 0;
    }
    template<class T>
    FireFloat(const T &v)
    {
    val = (FLOAT_TYPE)v;
    }
    FireFloat(const FireFloat &v)
    {
    val = v.val;
    }
    оператор приведения
    Код (Text):
        operator FIRE_INLINE FLOAT_TYPE() const
    {
    return val;
    }
    все обычные операторы
    Код (Text):
        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;
    }
    Пропатченные операторы сравнения
    Код (Text):
        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));
    }
    Поле
    Код (Text):
    private:
    FLOAT_TYPE val;
    };
    Собственно, был замечен только один минус этого решения, и с ним мы смогли смириться.
    Вылетел объявленный для другого типа (вектора) operator*(Ffloat, Vector) - скалярное умножение константы на вектор. Произошло это по очень простой причине. Пока Ffloat был всего лишь тайпдефом встроенного флота, строчка типа
    Код (Text):
    11*(Vector)a
    выполнялась очень просто - 11 приводилось к float'у и вызывался оператор вектора. А теперь 11 приводится к FireFloat'у и, соответсвенно, вызвается его оператор умножения, возвращающий не Vector, как было раньше, а FireFloat.

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

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

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

Поделиться этой страницей