От:
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..
Здравствуйте, zip_, Вы писали:
_>ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..
А ты сделай всё то же самое на языке, где нет шаблонов — введи внешние функции для инициализации и арифметики над этими size, point, rect, region... потом поддержи плавающую арифметику (скопипастить всё два раза)... потом исправь свеженайденные ошибки... Тогда посмотрим, что ты будешь ненавидеть.
Перекуём баги на фичи!
Здравствуйте, 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__
_>
_>гляньте, может еще чего упустил.
Перекуём баги на фичи!
От:
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) будут сгенерированы автоматически.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
От:
Patalog
Дата: 26.11.04 08:26
Оценка:
Здравствуйте, folk, Вы писали:
[]
F>Например, не вижу смысла в операции size<short> + size<int>, и неясно, какой же тип она возвращать (в твоем коде — size<short>).
Мне понравилось
это
Почетный кавалер ордена Совка.
От:
zip_
Дата: 26.11.04 08:39
Оценка:
_>>ненавижу этот язык, пойду что ли напьюсь, а то писать еще point, rect, region etc..
К>А ты сделай всё то же самое на языке, где нет шаблонов — введи внешние функции для инициализации и арифметики над этими size, point, rect, region... потом поддержи плавающую арифметику (скопипастить всё два раза)... потом исправь свеженайденные ошибки... Тогда посмотрим, что ты будешь ненавидеть.
Про ненавижу — это была шутка. Иначе бы я не писал на нем. Альтернатив нет на сегодняшний день (или есть?).
Но тем не менее многословность в языке IMHO присутствует.
От:
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]: ссылка не открывается (-)
Здравствуйте, zip_, Вы писали:
_>*
наверное имелось ввиду
http://rsdn.ru/Forum/Message.aspx?mid=342154&only=1Автор: WolfHound Дата: 01.08.03
... << RSDN@Home 1.1.3 stable >>
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить