краткость С++
От: zip_ Россия  
Дата: 25.11.04 17:39
Оценка: :)
вот во что могут превратиться две строчки кода типа

struct size {
  unsigned w;
  unsigned h;
}


->


#ifndef __z_size_inc__
#define __z_size_inc__

#include <cassert>
#include <algorithm> // for std::swap
#include <limits> // std::numeric_limits

namespace z {

template<typename>
class basic_size;

typedef basic_size<unsigned> size;

template<typename T>
class basic_size {
public:
    explicit basic_size(T w=0, T h=0):
        w_(w), h_(h) {}

    template<typename U>
    explicit basic_size(const basic_size<U>& s):
        w_(s.w_), h_(s.h_) {}

    template<typename U>
    basic_size& operator=(const basic_size<U>& s) { 
        basic_size<T>(s).swap(*this); 
        return *this; 
    }


    bool empty() const
        { return w_==0 && h_==0; }

    T w() const
        { return w_; }

    T h() const
        { return h_; }


    void setw(T w)
        { w_=w; }

    void seth(T h)
        { h_=h; }

    void set(T w, T h)
        { setw(w); seth(h); }


    template<typename U>
    bool operator==(const basic_size<U>& s) const
        { return w_==s.w_ && h_==s.h_; }

    template<typename U>
    bool operator!=(const basic_size<U>& s) const 
        { return !(*this==s); }


    const basic_size& operator+=(T d) {
        assert((std::numeric_limits<T>::max()-d>=w_) &&
            (std::numeric_limits<T>::max()-d>=h_));
        w_+=d; h_+=d; 
        return *this; 
    }

    template<typename U>
    const basic_size& operator+=(const basic_size<U>& s) {
        assert((std::numeric_limits<T>::max()-s.w_>=w_) &&
            (std::numeric_limits<T>::max()-s.h_>=h_));
        w_+=s.w_; h_+=s.h_; 
        return *this; 
    }


    const basic_size& operator-=(T d) { 
        assert(d<w_ && d<h_);
        w_-=d; h_-=d; 
        return *this; 
    }

    template<typename U>
    const basic_size& operator-=(const basic_size<U>& s) { 
        assert(s.w_<w_ && s.h_<h_);
        w_-=s.w_; h_-=s.h_;
        return *this; 
    }


    const basic_size& operator*=(T k) { 
        w_*=k; h_*=k; 
        return *this; 
    }

    template<typename U>
    const basic_size& operator*=(const basic_size<U>& s) { 
        w_*=s.w_; h_*=s.h_; 
        return *this; 
    }


    const basic_size& operator/=(T k) { 
        assert(k!=0);    
        w_/=k; h_/=k; 
        return *this; 
    }

    template<typename U>
    const basic_size& operator/=(const basic_size<U>& s) { 
        assert(s.w_!=0 && s.h_!=0);
        w_/=s.w_; h_/=s.h_; 
        return *this; 
    }


    void swap(basic_size& s) {
        std::swap(w_, s.w_);
        std::swap(h_, s.h_);
    }

private:

    template<typename U>
    friend class basic_size;

    T w_;
    T h_;
};

template<typename T>
basic_size<T> operator+(const basic_size<T>& s, T d) 
    { return basic_size<T>(s)+=d; }

template<typename T, typename U>
basic_size<T> operator+(const basic_size<T>& s1, const basic_size<U>& s2) 
    { return basic_size<T>(s1)+=s2; }

template<typename T>
basic_size<T> operator-(const basic_size<T>& s, T d) 
    { return basic_size<T>(s)-=d; }

template<typename T, typename U>
basic_size<T> operator-(const basic_size<T>& s1, const basic_size<U>& s2) 
    { return basic_size<T>(s1)-=s2; }

template<typename T>
basic_size<T> operator*(const basic_size<T>& s, T d) 
    { return basic_size<T>(s)*=d; }

template<typename T, typename U>
basic_size<T> operator*(const basic_size<T>& s1, const basic_size<U>& s2) 
    { return basic_size<T>(s1)*=s2; }

template<typename T>
basic_size<T> operator/(const basic_size<T>& s, T d) 
    { return basic_size<T>(s)/=d; }

template<typename T, typename U>
basic_size<T> operator/(const basic_size<T>& s1, const basic_size<U>& s2) 
    { return basic_size<T>(s1)/=s2; }

} // namespace z

#endif //__z_size_inc__


гляньте, может еще чего упустил.

ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..

Re: краткость С++
От: Кодт Россия  
Дата: 25.11.04 17:48
Оценка: 1 (1) +4 :)
Здравствуйте, zip_, Вы писали:

_>ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..


А ты сделай всё то же самое на языке, где нет шаблонов — введи внешние функции для инициализации и арифметики над этими size, point, rect, region... потом поддержи плавающую арифметику (скопипастить всё два раза)... потом исправь свеженайденные ошибки... Тогда посмотрим, что ты будешь ненавидеть.
Перекуём баги на фичи!
Re: краткость С++
От: Кодт Россия  
Дата: 25.11.04 18:08
Оценка: 11 (2) +1
Здравствуйте, zip_, Вы писали:

_>
_>#ifndef __z_size_inc__
_>#define __z_size_inc__

_>#include <cassert>
_>#include <algorithm> // for std::swap
_>#include <limits> // std::numeric_limits

_>namespace z { // очень содержательное имя у namespace :-\

_>template<typename>
_>class basic_size;

_>typedef basic_size<unsigned> size;

_>template<typename T>
_>class basic_size {
_>public:
_>    explicit basic_size(T w=0, T h=0): // имхо, это извращение.
_>        w_(w), h_(h) {}
        // нужно два конструктора - без параметров и почленный (оба члена обязательны)

_>    template<typename U>
_>    explicit basic_size(const basic_size<U>& s):
_>        w_(s.w_), h_(s.h_) {}

_>    template<typename U>
_>    basic_size& operator=(const basic_size<U>& s) { 
_>        basic_size<T>(s).swap(*this); 
_>        return *this; 
_>    }
        // зачем эксплицитный конструктор копирования из basic_size<U>,
        // если у тебя есть оператор присваивания этого типа?
        // Надо забить на оператор присваивания болт, пусть дефолтный работает.
        // И реализация через swap неэффективна.

_>    bool empty() const
_>        { return w_==0 && h_==0; }

_>    T w() const
_>        { return w_; }

_>    T h() const
_>        { return h_; }


_>    void setw(T w)
_>        { w_=w; }

_>    void seth(T h)
_>        { h_=h; }

_>    void set(T w, T h)
_>        { setw(w); seth(h); }

_>    template<typename U>
_>    bool operator==(const basic_size<U>& s) const
_>        { return w_==s.w_ && h_==s.h_; }
        // По смыслу неправомерно.
        // Если ты будешь сравнивать в плавающей арифметике или знаковые/беззнаковые, огребёшь проблемы.
        // С точки зрения безопасности программирования, нужно сравнивать только со своим типом
        // (да и то, с оговорками про плавающую арифметику)

_>    template<typename U>
_>    bool operator!=(const basic_size<U>& s) const 
_>        { return !(*this==s); }


_>    const basic_size& operator+=(T d) {
_>        assert((std::numeric_limits<T>::max()-d>=w_) &&
_>            (std::numeric_limits<T>::max()-d>=h_));
_>        w_+=d; h_+=d; 
_>        return *this; 
_>    }
        // Очень опасный по смыслу оператор: сумма вектора со скаляром.
        // Математически, это ботва. Хочешь явно инкрементировать все компоненты сразу -
        // напиши функцию (функции) с человеческим именем. Это будет наглядно
        // Например, extend_w(w), extend_h(h), extend_wh(w,h), extend_wh(wh)

        // Тем более, что можно складывать векторы разной природы - например, размеры и точки.
        // А у тебя точка здесь выступит как скаляр, что не есть правильно.

_>    template<typename U>
_>    const basic_size& operator+=(const basic_size<U>& s) {
_>        assert((std::numeric_limits<T>::max()-s.w_>=w_) &&
_>            (std::numeric_limits<T>::max()-s.h_>=h_));
_>        w_+=s.w_; h_+=s.h_; 
_>        return *this; 
_>    }

_>    const basic_size& operator-=(T d) { 
_>        assert(d<w_ && d<h_);
_>        w_-=d; h_-=d; 
_>        return *this; 
_>    }

_>    template<typename U>
_>    const basic_size& operator-=(const basic_size<U>& s) { 
_>        assert(s.w_<w_ && s.h_<h_);
_>        w_-=s.w_; h_-=s.h_;
_>        return *this; 
_>    }

_>    const basic_size& operator*=(T k) { 
_>        w_*=k; h_*=k; 
_>        return *this; 
_>    }

_>    template<typename U>
_>    const basic_size& operator*=(const basic_size<U>& s) { 
_>        w_*=s.w_; h_*=s.h_; 
_>        return *this; 
_>    }
        // Опять математическая ботва. Умножение векторов - это:
        // - скалярное умножение, на выходе скаляр
        // - векторное умножение, на выходе ортогональный обоим тензор (в 3-мерном пространстве - вектор)
        // - тензорное умножение, на выходе - матрица
        // - почленное умножение, на выходе - вектор
        // Почему ты здесь выбрал один из возможных? И как он соотносится с геометрическим смыслом типа?

_>    const basic_size& operator/=(T k) { 
_>        assert(k!=0);    
_>        w_/=k; h_/=k; 
_>        return *this; 
_>    }

_>    template<typename U>
_>    const basic_size& operator/=(const basic_size<U>& s) { 
_>        assert(s.w_!=0 && s.h_!=0);
_>        w_/=s.w_; h_/=s.h_; 
_>        return *this; 
_>    }


_>    void swap(basic_size& s) {
_>        std::swap(w_, s.w_);
_>        std::swap(h_, s.h_);
_>    }

_>private:

_>    template<typename U>
_>    friend class basic_size;
        // Если принять во внимание всё сказанное выше, то дружба с коллегами не нужна.
        // Тем более, что у них есть открытые члены для доступа - w(), h().

_>    T w_;
_>    T h_;
_>};

_>template<typename T>
_>basic_size<T> operator+(const basic_size<T>& s, T d) 
_>    { return basic_size<T>(s)+=d; }

_>template<typename T, typename U>
_>basic_size<T> operator+(const basic_size<T>& s1, const basic_size<U>& s2) 
_>    { return basic_size<T>(s1)+=s2; }

_>template<typename T>
_>basic_size<T> operator-(const basic_size<T>& s, T d) 
_>    { return basic_size<T>(s)-=d; }

_>template<typename T, typename U>
_>basic_size<T> operator-(const basic_size<T>& s1, const basic_size<U>& s2) 
_>    { return basic_size<T>(s1)-=s2; }

_>template<typename T>
_>basic_size<T> operator*(const basic_size<T>& s, T d) 
_>    { return basic_size<T>(s)*=d; }

_>template<typename T, typename U>
_>basic_size<T> operator*(const basic_size<T>& s1, const basic_size<U>& s2) 
_>    { return basic_size<T>(s1)*=s2; }

_>template<typename T>
_>basic_size<T> operator/(const basic_size<T>& s, T d) 
_>    { return basic_size<T>(s)/=d; }

_>template<typename T, typename U>
_>basic_size<T> operator/(const basic_size<T>& s1, const basic_size<U>& s2) 
_>    { return basic_size<T>(s1)/=s2; }

// Ты ещё забыл сделать внешний swap().
// Поскольку поиск Кёнига в некоторых компиляторах реализован половинчато
// то есть смысл вынести swap за пределы namespace.

_>} // namespace z

_>#endif //__z_size_inc__
_>


_>гляньте, может еще чего упустил.
Перекуём баги на фичи!
Re: краткость С++
От: folk Россия  
Дата: 26.11.04 03:36
Оценка: +1
Здравствуйте, zip_, Вы писали:

_>вот во что могут превратиться две строчки кода типа


_>
_>struct size {
_>  unsigned w;
_>  unsigned h;
_>}
_>


[]

_>гляньте, может еще чего упустил.


_>ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..


_>


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

Оно действительно надо, инкапсулироать этои структуры и делать point, rect, etc шаблонами?

Если все-таки надо, то на мой взгляд, между объектами различных типов (например size<short> и size<int>) допустима только операция явного приведения, а все остальное излишне и вредно. Например, не вижу смысла в операции size<short> + size<int>, и неясно, какой же тип она возвращать (в твоем коде — size<short>).

Определять кучу операторов действительно утомительно. Советую посмотреть в сторону boost::operators. Используя его, достаточно определить только функцию-член size size::operator+=(T), а свободные функции size operator+(size, T) и size operator+(T,size) будут сгенерированы автоматически.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[2]: краткость С++
От: Patalog Россия  
Дата: 26.11.04 08:26
Оценка:
Здравствуйте, folk, Вы писали:

[]

F>Например, не вижу смысла в операции size<short> + size<int>, и неясно, какой же тип она возвращать (в твоем коде — size<short>).


Мне понравилось это
Почетный кавалер ордена Совка.
Re[2]: краткость С++
От: zip_ Россия  
Дата: 26.11.04 08:39
Оценка:
_>>ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..

К>А ты сделай всё то же самое на языке, где нет шаблонов — введи внешние функции для инициализации и арифметики над этими size, point, rect, region... потом поддержи плавающую арифметику (скопипастить всё два раза)... потом исправь свеженайденные ошибки... Тогда посмотрим, что ты будешь ненавидеть.


Про ненавижу — это была шутка. Иначе бы я не писал на нем. Альтернатив нет на сегодняшний день (или есть?).
Но тем не менее многословность в языке IMHO присутствует.
Re[2]: краткость С++
От: zip_ Россия  
Дата: 26.11.04 09:04
Оценка:
F>Оно действительно надо, инкапсулироать этои структуры и делать point, rect, etc шаблонами?

F>Если все-таки надо, то на мой взгляд, между объектами различных типов (например size<short> и size<int>) допустима только операция явного приведения, а все остальное излишне и вредно. Например, не вижу смысла в операции size<short> + size<int>, и неясно, какой же тип она возвращать (в твоем коде — size<short>).


Это библиотечный код. В зависимости от окружения может быть использовано basic_size<unsigned char>, basic_size<unsigned short>, size (basic_size<unsigned int>) или что-то иное. Возможно смешение этих типов действительно излишне..

F>Определять кучу операторов действительно утомительно. Советую посмотреть в сторону boost::operators. Используя его, достаточно определить только функцию-член size size::operator+=(T), а свободные функции size operator+(size, T) и size operator+(T,size) будут сгенерированы автоматически.


Не хотелось бы библиотеку делать зависимой от boost
Re[3]: ссылка не открывается (-)
От: zip_ Россия  
Дата: 26.11.04 09:05
Оценка:
*
Re[2]: спасибо за конструктив, учту (-)
От: zip_ Россия  
Дата: 26.11.04 09:15
Оценка:
*
Re[4]: ссылка не открывается (-)
От: yxiie Украина www.enkord.com
Дата: 26.11.04 09:39
Оценка: +1
Здравствуйте, zip_, Вы писали:

_>*


наверное имелось ввиду
http://rsdn.ru/Forum/Message.aspx?mid=342154&amp;only=1
Автор: WolfHound
Дата: 01.08.03
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.