Вот, достало ловить ошибки с неинициализованными членами больших классов, вида
class MyBigClass
{
int m_mySmallValue;
...
MyBigClass();
MyBigClass(X x, Y y, Z z);
... и еще куча конструкторов
};
MyBigClass::MyBigClass(xxxx) : ......
// а про малюсенькое данное забыли :(
{
}
Поэтому сделал шаблон самоинициализирующихся значений простых типов (числа, указатели).
template< class T, T i = 0 >
class auto_value
{
T t_;
public:
typedef T data_t;
typedef auto_value& self_t;
// конструктор по умолчанию - главное достоинство этой тулзыinline auto_value() : t_(i) {}
// конструктор с 1 параметром (в том числе - конструктор копирования)template< class V >
inline auto_value(V v) : t_(v) {}
// доступ к данномуinline const T& data() const { return t_; }
inline T& data() { return t_; }
// считается, что исходный тип - простойinline operator T () const { return t_; }
inline operator T& () { return t_; }
// операторы присваиванияtemplate< class V > inline self_t operator = (V v) { t_ = v; return *this; }
template< class V > inline self_t operator += (V v) { t_ += v; return *this; }
template< class V > inline self_t operator -= (V v) { t_ -= v; return *this; }
template< class V > inline self_t operator *= (V v) { t_ *= v; return *this; }
template< class V > inline self_t operator /= (V v) { t_ /= v; return *this; }
template< class V > inline self_t operator %= (V v) { t_ %= v; return *this; }
template< class V > inline self_t operator &= (V v) { t_ &= v; return *this; }
template< class V > inline self_t operator |= (V v) { t_ |= v; return *this; }
template< class V > inline self_t operator ^= (V v) { t_ ^= v; return *this; }
template< class V > inline self_t operator <<= (V v) { t_ <<= v; return *this; }
template< class V > inline self_t operator >>= (V v) { t_ >>= v; return *this; }
};
Такая куча операторов ??= нужна, чтобы не писать постоянно "myvalue.data() ??= 123"
Пример использования:
class MyBigClass
{
auto_value<bool/* , false */ > m_bEnabled;
...
public:
MyBigClass() {} // все члены инициализируются сами - как сумеют
...
bool isEnabled() { return m_bEnabled; } // получим false, а не 0xCDCDCDCDvoid setEnabled(bool b) { m_bEnabled = b; }
...
};
К>Заведомо не лучше. Невозможно будет использовать неявное преобразование типов.
Проверял на GCC 3.1. Там все нормально. Проходит без ругательств. В том числе и неявное преобразование типов с операторами возвращающими ссылку на константу. Вообще то я не совсем понимаю, почему не проходит неявное преобразование с ссылками на константы, а с обычными проходит? Приведи пример, пожалуйста. Просто я стараюсь делать как можно более похожие интерфейсы функций/операторов для константного и неконстантного объекта. Привычка.
К>Если определен operator T() const К>то нужда у них отпадает.
Угу. Сорри.
Здравствуйте, Atilla, Вы писали:
C>>А как же все остальные? сравнение, сложение, сдвиги, инкрементация и т.п. и т.д.? A>это для простеньких-то типов (int, char, void*) ?
А зачем их дискриминировать? Чем они хуже?
C>>>inline operator T const &() const { return t_; }
К>>Заведомо не лучше. Невозможно будет использовать неявное преобразование типов.
C>Проверял на GCC 3.1. Там все нормально. Проходит без ругательств. В том числе и неявное преобразование типов с операторами возвращающими ссылку на константу. Вообще то я не совсем понимаю, почему не проходит неявное преобразование с ссылками на константы, а с обычными проходит? Приведи пример, пожалуйста. Просто я стараюсь делать как можно более похожие интерфейсы функций/операторов для константного и неконстантного объекта. Привычка.
У меня тоже эта привычка. Однако такой пример:
Если определить оператор "значение" как
operator const T&() const
то имеем ошибки на всех операциях над значением: (компилятор VC6sp5)
class CChannel ...
{
...
auto_value<bool> m_bEnabled;
...
public:
STDMETHOD(notifyReceiver)()
{
if( !m_bEnabled )
// error C2675: unary '!' :
// 'class auto_value<bool,0>' does not define this operator or a conversion to a type
// acceptable to the predefined operator
...
}
...
};
(может быть, где-то в другом месте вылезет ambiguous call).
А пока я добавил эту тулзу вот с этими тремя операторами в большой проект, и надеюсь поиметь отзывы от сотрудников в течение недели.
К>(может быть, где-то в другом месте вылезет ambiguous call). К>А пока я добавил эту тулзу вот с этими тремя операторами в большой проект, и надеюсь поиметь отзывы от сотрудников в течение недели.
Кстати, если объявлены два таких оператора
inline operator T const &() const { return t_; }
inline operator T () const { return t_; }
Здравствуйте, comer, Вы писали:
C>Кстати, если объявлены два таких оператора C>
C>inline operator T const &() const { return t_; }
C>inline operator T () const { return t_; }
C>
C>то GCC 3.1, не может откомпилировать вот это:
Екандыбабай! А GCC 2.7.2 — сожрал (да, старый, да, кривой... но единственно доступный для целевой платформы).
Поскольку мне более всего важна совместимость со своей задачей, оставляю себе трех-операторный вариант. А дальше — поживем, увидим.
А безшаблонный вариант, интересно, как себя ведет?
Еще можно на Comeau-online проверить, но это — позже.
C>Интересно, кстати, какой из этих операторов в таком случае будет использовать VC?
Достаточно воткнуть трассирову, или же Александеску'вские compile-time check.
К> // доступ к данному
К> inline const T& data() const { return t_; }
К>
Саттер и ISO/IEC 14882 пишут, что функция вида:
T f();
где T является встроенным типом, всегда возвращает r-value. cv-квалифиатор не может быть применен к r-value, и это может помешать инстанцированию шаблонов.
Т.е., чтобы это было совсем корректно, возможно, придется воспользоваться type traits.
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Кодт, Вы писали:
К>>
К>> // доступ к данному
К>> inline const T& data() const { return t_; }
К>>
ME>Саттер и ISO/IEC 14882 пишут, что функция вида: ME>
ME>T f();
ME>
ME>где T является встроенным типом, всегда возвращает r-value. cv-квалифиатор не может быть применен к r-value, и это может помешать инстанцированию шаблонов. ME>Т.е., чтобы это было совсем корректно, возможно, придется воспользоваться type traits.
И именно поэтому я пишу не T data() const, а const T& data() const.
Чтобы получить константное l-value (и в дальнейшем, например, использовать указатель на константу:
Здравствуйте, Andrew S, Вы писали:
AS>Возможно, я скажу глупость, но я бы использовал template < class T, T i = T() > AS>что дает таки большую свободу в типах, нежели инициализирование нулем.
Вопрос: int() == 0?
А вообще, можно же сделать шаблон для инициализации POD-структур .
template< class POD >
struct auto_pod : public POD
{
auto_pod() { memset( static_cast<POD*>(this), 0, sizeof(POD) ); }
};
(тут нужно быть аккуратным с пустыми структурами, т.к. их sizeof() == 1).
Здравствуйте, Кодт, Вы писали:
К>И именно поэтому я пишу не T data() const, а const T& data() const. К>Чтобы получить константное l-value (и в дальнейшем, например, использовать указатель на константу:
Здравствуйте, Блудов Павел, Вы писали:
К>>(тут нужно быть аккуратным с пустыми структурами, т.к. их sizeof() == 1).
БП>Этот вопрос решается простым наследованием структуры с одним полем байтовой длины:
БП>Если POD без полей, то 1 == sizeof(POD), и 0 == _offsetof(_PODSize, _PODSize::_Dummy).
Хотя было бы полезно написать шаблон приблизительно такого вида:
template< class T >
struct struct_traits
{
.....
enum { isNotEmptyPOD = ..... };
.....
template < bool b >
class _auto_pod_impl : public T
{ };
template <>
class _auto_pod_impl<false> // cпециальная версия для структур с нулевым размером
: public T // для возможности преобразования типов
{
_auto_pod_impl() {}
_auto_pod_impl(const T&) {}
void operator=(const T&) {}
};
typedef _auto_pod_impl< isNotEmptyPOD > auto_pod;
};
template< class T >
class auto_pod : struct_traits<T>::auto_pod
{ };
Такой код может быть написан только в реализации стандартной библиотеки, или в компиляторно-зависимой библиотеке. Для всего остального разыменование нулевого указателя не является легальным C++ (p->m => (*(p)).m (см. 5.2.5/3)).
Ну, и про идентификаторы тоже... Все, что начинается с _<Большая латинская> — зарезервировано.
Работает точно так же. Прочитал внимательно 5.2.5 Class member access [expr.ref].
Ни слова о нулевом указателе. Нельзя ли подробнее, что же я упустил?
Kaa>Ну, и про идентификаторы тоже... Все, что начинается с _<Большая латинская> — зарезервировано.
Вы про auto_pod::_PODSize? Он начинается с маленькой латинской буквы.
Указанное Вами правило (17.4.3.1.2) относится только к глобальным именам.
Или у нас стандарты разные
Здравствуйте, Блудов Павел, Вы писали:
Kaa>>разыменование нулевого указателя не является легальным C++ (p->m => (*(p)).m (см. 5.2.5/3)).
БП>Прочитал внимательно 5.2.5 Class member access [expr.ref]. БП>Ни слова о нулевом указателе. Нельзя ли подробнее, что же я упустил?
1.9/4, к примеру, говорит, что разыменование нулевого указателя порождает неопределенное поведение.
БП>Указанное Вами правило (17.4.3.1.2) относится только к глобальным именам.
Нет, стандарты у нас одинаковые. Тут я не прав. Спасибо.
Здравствуйте, Кодт, Вы писали:
К>Вот, достало ловить ошибки с неинициализованными членами больших классов, вида
... skip() ... К>[/c]
А как можно модифицировать этот замечательный класс, что бы можно было писать нечто
auto_value<int> i = 0;
auto_value<int> j = i;
А то ругается на это, говорит : error C2440: 'initializing' : cannot convert from 'class auto_value<int,0>' to 'class auto_value<int,0>'
No copy constructor available for class 'auto_value<int,0>'
без этого в конструкторах копии приходится писать
Kaa>Такой код может быть написан только в реализации стандартной библиотеки, или в компиляторно-зависимой библиотеке. Для всего остального разыменование нулевого указателя не является легальным C++ (p->m => (*(p)).m (см. 5.2.5/3)).
Он там и написан. <cstddef>:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
18.1.5
The macro offsetof accepts a restricted set of type arguments in this International Standard. type shall be a POD structure or a POD union (clause 9). The result of applying the offsetof macro to a field that is a static data member or a function member is undefined.
Это, конечно, лишает массы удобств. Но и необходимо только для тяжелых классов, которые лучше сконструировать и не трогать.
А для легких, с конструктором по умолчанию, и которым присваивать можно:
class Foo
{
Bar bar;
Foobar foobar;
struct AllMyStaff
{
AllMyStaff()
{
bar = Bar(barParam);
foobar = Foobar(foobarParam);
}
} allMyStaff;
};
Кроме того конструктор AllMyStaff ( хорошего названия я так и не придумал никогда, кто придумает скажите, а то уже надоели всякие X и прочие глупости ) можно сделать с параметром. Забыть его теперь нельзя, но можно передать нужные параметры.
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Рома Мик, Вы писали:
ME>[]
РМ>>А для легких, с конструктором по умолчанию, и которым присваивать можно:
РМ>>
РМ>> }
РМ>> } allMyStaff;
РМ>>};
РМ>>
ME>Ты пробовал эту херню скомпилить хоть разок? Советую попробовать.
Пробовал, но достаточно давно. Потому забыл подробности. Это довольно редко нужный код, т.к. редко нельзя унаследоваться от AllMyStaff. В этом варианте надо передавать this в конструктор AllMyStaff.
БП>Хотя в этом случае, нилем имеет смысл прописать только первые 9-ть байт. БП>Есть идеи?
Нет никаких идей. Это — суровая правда жизни
struct aa
{
__int8 i2;
__int64 i1;
};
Здесь размер — тоже 16 и надо инициализировать все 16 байт. Как отличить эти два случая? Можно, конечно, тупо и грязно использовать #pragma pack, но на Intel это приведет к резкой деградации производительности, а на других платформах (Sun, SGI, если там есть аналогичная прагма) — вообще не будет работать, там сразу "автобусная ошибка" и до свидания...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Очень хорошая идея , но имеет небольшой недостаток — переменный инициализируются полько в начале , а что если я хочу сбросить все переменные в начальное состояние ?
Есть решение но с использованием макросов:
template<class T, T i = T()>
class auto_value
{
T t_;
public:
typedef T data_t;
typedef auto_value& self_t;
// конструктор по умолчанию - главное достоинство этой тулзыinline auto_value() : t_(i) {}
// конструктор с 1 параметром (в том числе - конструктор копирования)template< class V >
inline auto_value(V v) : t_(v) {}
// доступ к данномуinline const T& data() const { return t_; }
inline T& data() { return t_; }
// считается, что исходный тип - простойinline operator T () const { return t_; }
inline operator T& () { return t_; }
// операторы присваиванияtemplate< class V > inline self_t operator = (V v) { t_ = v; return *this; }
template< class V > inline self_t operator += (V v) { t_ += v; return *this; }
template< class V > inline self_t operator -= (V v) { t_ -= v; return *this; }
template< class V > inline self_t operator *= (V v) { t_ *= v; return *this; }
template< class V > inline self_t operator /= (V v) { t_ /= v; return *this; }
template< class V > inline self_t operator %= (V v) { t_ %= v; return *this; }
template< class V > inline self_t operator &= (V v) { t_ &= v; return *this; }
template< class V > inline self_t operator |= (V v) { t_ |= v; return *this; }
template< class V > inline self_t operator ^= (V v) { t_ ^= v; return *this; }
template< class V > inline self_t operator <<= (V v) { t_ <<= v; return *this; }
template< class V > inline self_t operator >>= (V v) { t_ >>= v; return *this; }
// по умалчаниюinline void default_() { t_=i; }
};
#define BEGIN_AUTO_MAP() \
public: \
void default_() \
{
#define AUTO_VALUE(v) \
v.default_();
#define END_AUTO_MAP() \
}
class Test
{
auto_value<int,5> i;
auto_value<char,'a'> c;
BEGIN_AUTO_MAP()
AUTO_VALUE(i)
AUTO_VALUE(c)
END_AUTO_MAP()
};
void main()
{
Test test;
test.i=10;
test.c='f';
test.default_();
}
Здравствуйте, Кодт, Вы писали:
К>Вот, достало ловить ошибки с неинициализованными членами больших классов
Я для таких классов переопределяю оператор new, в котором обнуляю выделяемую память.
Все конструкторы переношу в private/protected и оставляю только статические функции типа CreateInstance с тем-же набором параметров, что и в конструкторах.
Здравствуйте, MShura, Вы писали:
MS>Я для таких классов переопределяю оператор new, в котором обнуляю выделяемую память. MS>Все конструкторы переношу в private/protected и оставляю только статические функции типа CreateInstance с тем-же набором параметров, что и в конструкторах.
Во-первых, ты для каждого своего класса вынужден совершить ряд излишних телодвижений.
Во-вторых, не всегда это можно сделать — например, если я пишу кокласс с использованием ATL — там всегда используется единственный конструктор (без параметров) и к тому же класс заведомо не финальный: создается CComObject<MyClass> который является потомком.
Что же мне, ATL переписывать, чтобы там new память чистил?
Любая ситуация с наследованием от данного класса — и все, приплыли.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, MShura, Вы писали:
MS>>Я для таких классов переопределяю оператор new, в котором обнуляю выделяемую память. MS>>Все конструкторы переношу в private/protected и оставляю только статические функции типа CreateInstance с тем-же набором параметров, что и в конструкторах.
К>Во-первых, ты для каждого своего класса вынужден совершить ряд излишних телодвижений. К>Во-вторых, не всегда это можно сделать — например, если я пишу кокласс с использованием ATL — там всегда используется единственный конструктор (без параметров) и к тому же класс заведомо не финальный: создается CComObject<MyClass> который является потомком. К>Что же мне, ATL переписывать, чтобы там new память чистил? К>Любая ситуация с наследованием от данного класса — и все, приплыли.
Насколько я помню, если оператор new есть у одного из базовых классов, то для производных он также будет вызываться (соответственно размер требуемой памяти будет передаваться нужный).
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, MShura, Вы писали:
MS>>Я для таких классов переопределяю оператор new, в котором обнуляю выделяемую память. MS>>Все конструкторы переношу в private/protected и оставляю только статические функции типа CreateInstance с тем-же набором параметров, что и в конструкторах.
Это я делаю для классов, которыми могут пользоваться другие программисты. Таким образом я просто защищаюсь от создания экзампляра на стеке. Если наверняка известно, что данный класс ВСЕГДА будет создаваться с помощью оператора new (например в ATL/COM), то никаких лишиних телодвижений и не надо.
Забыл написать в прошлом посте, что у меня для этих целей есть простенький класс, у которого переопределены new + delete. Если мне нужна их функциональность, то я просто добавляю его в список базовых классов.
Здравствуйте, MShura, Вы писали:
MS>Это я делаю для классов, которыми могут пользоваться другие программисты. Таким образом я просто защищаюсь от создания экзампляра на стеке. Если наверняка известно, что данный класс ВСЕГДА будет создаваться с помощью оператора new (например в ATL/COM), то никаких лишиних телодвижений и не надо. MS>Забыл написать в прошлом посте, что у меня для этих целей есть простенький класс, у которого переопределены new + delete. Если мне нужна их функциональность, то я просто добавляю его в список базовых классов.
А если экземпляр — это член другого класса, тогда как быть? Тут не все так просто...
Кроме того, auto_value позволяет инициализировать переменные любым нужным значением
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, MShura, Вы писали:
MS>>Это я делаю для классов, которыми могут пользоваться другие программисты. Таким образом я просто защищаюсь от создания экзампляра на стеке. Если наверняка известно, что данный класс ВСЕГДА будет создаваться с помощью оператора new (например в ATL/COM), то никаких лишиних телодвижений и не надо. MS>>Забыл написать в прошлом посте, что у меня для этих целей есть простенький класс, у которого переопределены new + delete. Если мне нужна их функциональность, то я просто добавляю его в список базовых классов.
К>А если экземпляр — это член другого класса, тогда как быть? Тут не все так просто...
А в чем проблема?Основное условие — все экземпляры/подэкземпляры должны создаваться через new.
Это так сказать цена за удобство.
К>Кроме того, auto_value позволяет инициализировать переменные любым нужным значением
Для таких целей тот подход бесполезен. К>
Здравствуйте, MShura, Вы писали:
К>>А если экземпляр — это член другого класса, тогда как быть? Тут не все так просто... MS>А в чем проблема?Основное условие — все экземпляры/подэкземпляры должны создаваться через new. MS>Это так сказать цена за удобство.
Тебе не кажется, что каждый int на куче создавать — это дорогая цена?
Кроме того, такая утилитка
Здравствуйте, MShura, Вы писали:
MS>Вообще-то твой начальный пост содержал строку: MS>"Вот, достало ловить ошибки с неинициализованными членами больших классов, вида"
MS>Я сказал, как я поступаю в таком случае. А теперь у тебя от большого класса остался только int?
Неинициализированные члены большого класса.
class SuperPuper
{
public:
SuperPuper() : x_(10), y_(20), z_(30), yes_(true), no_(false), cancel_(false) {}
SuperPuper(int x, int y, int z) : x_(x), y_(y), z_(z), yes_(true), no_(false), cancel_(false) {}
SuperPuper(int ync) : x_(10), y_(20), z_(30), yes_(ync==0), no_(ync==1), cancel_(ync==2) {}
private:
int x_;
int y_;
int z_;
bool yes_, no_, cancel_;
...
...
...
char c_; // добавили в новой версии, в конструкторы прописать забыли.
};
Для большого класса в любом случае существует конструктор, а порой и не один. Так что формально объект этого класса будет проинициализирован (а если нет конструктора без параметров — то компилятор еще и по пальцам надает за забывчивость) при включении его членом другого класса.
А вот для скалярных типов это действительно проблема.
Я еще раз хочу подчеркнуть: изыск возник как реальная потребность при разработке и сопровождении больших проектов.
С самого начала идея очень понравилась и немного развилась, давно практикую в своей работе такие вещи, вот решил поделиться мыслями:
class MyBigClass
{
auto_value<bool/* , false */ > m_bEnabled;
limit<auto_value<unsigned short, 5000 > 5000, 25000> m_PortNumber;
...
public:
MyBigClass() {} // все члены инициализируются сами - как сумеют
...
bool isEnabled() { return m_bEnabled; } // получим false, а не 0xCDCDCDCDvoid setEnabled(bool b) { m_bEnabled = b; }
...
};
В данном случае номер порта может присваиваться из определенного промежутка, в противном случае получите out_of_range.
Ну и имплементация limit достаточно проста:
template< typename T, size_t min, size_t max>
class limit : public T
{
public:
typedef T data_t;
typedef limit& self_t;
//default ctorinline limit() : T() {}
// ctor with 1 parameter( including copy constructor)template< class V >
inline limit(V v) : T(v) {}
//access to datainline const T& data() const { return (T&)*this; }
inline T& data() { return (T&)*this; }
// means that original type is simpleoperator T () const { return data(); }
operator const T& () const { return data(); }
operator T& () { return data(); }
//assignment operatorstemplate< class V > inline self_t operator = (V v)
{
if( v < min || v > max )
throw std::out_of_range("new value not in the range");
data() = v;
return *this;
}
template< class V > inline self_t operator += (V v)
{
T tmp = data();
tmp += v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator -= (V v)
{
T tmp = data();
tmp -= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator *= (V v)
{
T tmp = data();
tmp *= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator /= (V v)
{
T tmp = data();
tmp /= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator %= (V v)
{
T tmp = data();
tmp %= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator &= (V v)
{
T tmp = data();
tmp &= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator |= (V v)
{
T tmp = data();
tmp |= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator ^= (V v)
{
T tmp = data();
tmp ^= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator <<= (V v)
{
T tmp = data();
tmp <<= v;
*this = tmp;
return *this;
}
template< class V > inline self_t operator >>= (V v)
{
T tmp = data();
tmp >>= v;
*this = tmp;
return *this;
}
//prefixinline self_t operator ++ ()
{
T tmp = data();
++tmp;
*this = tmp;
return *this;
}
//postfixinline data_t operator ++ (int)
{
T tmp = data();
tmp++;
*this = tmp;
return data();
}
};
Подобными требованиями-атрибутами можно нагрузить любые члены класса, речь идет не только о лимитах, к примеру можно проверять строку на присвоение пустой строки ( not_empty_string атрибут ), другие требования, которые больше относятся к бизнес логике приложения... Таким образом это завернутое поле запросто может выродиться в полноценное свойство, об отсутствии которых многие сегодня сетуют, тогда значительно упростится кодирование функциональности структур данных, все проверки значений полей сосредоточятся в одних местах.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Здравствуйте, Batiskaf, Вы писали:
B>В данном случае номер порта может присваиваться из определенного промежутка, в противном случае получите out_of_range. B>Ну и имплементация limit достаточно проста:
B>
B>template< typename T, size_t min, size_t max>
B>class limit : public T
B>{
B>
А почему бы не воспользоваться предикатом ?
template<typename T, T t_min, T t_max, typename TPred = std::less<T> >
class limit_t
// : public T - лучше сделать не наследование, а аггрегацию, чтобы была возможность использовать простой тип, IMHO
{
T t;
public:
//...inline T& data() { return t; }
template< class V > inline self_t operator = (V v)
{
if( TPed(v, t_min)
throw std::out_of_range("new value not in the range - less than minimum");
if( TPred(t_max, v)
throw std::out_of_range("new value not in the range - more than maximum");
data() = v;
return *this;
}
};
Здравствуйте, _nn_, Вы писали:
__>Здравствуйте, Batiskaf, Вы писали:
B>>В данном случае номер порта может присваиваться из определенного промежутка, в противном случае получите out_of_range. B>>Ну и имплементация limit достаточно проста:
B>>
B>>template< typename T, size_t min, size_t max>
B>>class limit : public T
B>>{
B>>
__>А почему бы не воспользоваться предикатом ? __>
__>template<typename T, T t_min, T t_max, typename TPred = std::less<T> >
__>class limit_t
__>// : public T - лучше сделать не наследование, а аггрегацию, чтобы была возможность использовать простой тип, IMHO
__>{
__> T t;
__>public:
__> //...
__> inline T& data() { return t; }
__> template< class V > inline self_t operator = (V v)
__> {
__> if( TPred(v, t_min)
__> throw std::out_of_range("new value not in the range - less than minimum");
__> if( TPred(t_max, v)
__> throw std::out_of_range("new value not in the range - more than maximum");
__> data() = v;
__> return *this;
__> }
__>};
__>
для простых типов должна использоваться насадка auto_value, так что не вижу никаких препятствий для наследования. Что же касается параметризирования, то как сказано выше, атрибуты могут вкладываться один в другой, и тогда проблематично будет с этим:
limit_t<auto_value<int, 200>, 200, 100000> a;
лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Здравствуйте, Batiskaf, Вы писали:
B>Здравствуйте, _nn_, Вы писали:
__>>Здравствуйте, Batiskaf, Вы писали:
B>>>В данном случае номер порта может присваиваться из определенного промежутка, в противном случае получите out_of_range. B>>>Ну и имплементация limit достаточно проста:
B>>>
B>>>template< typename T, size_t min, size_t max>
B>>>class limit : public T
B>>>{
B>>>
__>>А почему бы не воспользоваться предикатом ? __>>
__>>template<typename T, T t_min, T t_max, typename TPred = std::less<T> >
__>>class limit_t
__>>// : public T - лучше сделать не наследование, а аггрегацию, чтобы была возможность использовать простой тип, IMHO
__>>{
__>> T t;
__>>public:
__>> //...
__>> inline T& data() { return t; }
__>> template< class V > inline self_t operator = (V v)
__>> {
__>> if( TPred(v, t_min)
__>> throw std::out_of_range("new value not in the range - less than minimum");
__>> if( TPred(t_max, v)
__>> throw std::out_of_range("new value not in the range - more than maximum");
__>> data() = v;
__>> return *this;
__>> }
__>>};
__>>
B>для простых типов должна использоваться насадка auto_value, так что не вижу никаких препятствий для наследования. Что же касается параметризирования, то как сказано выше, атрибуты могут вкладываться один в другой, и тогда проблематично будет с этим:
Наверное в большинстве случаев будут использоваться простые типы, а так для них придется еще использовать дополнительный класс.
А вообще можно сделать два класса, с наследованием и без
B>
B>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно.
Здесь вы говорите обратное от того что сказано вами выше
А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
P.S.
В вашем коде есть небольшой недочет, а имено :
Здравствуйте, _nn_, Вы писали:
__>Здравствуйте, Batiskaf, Вы писали:
B>>Здравствуйте, _nn_, Вы писали:
__>>>Здравствуйте, Batiskaf, Вы писали:
B>>>>В данном случае номер порта может присваиваться из определенного промежутка, в противном случае получите out_of_range. B>>>>Ну и имплементация limit достаточно проста:
B>>>>
B>>>>template< typename T, size_t min, size_t max>
B>>>>class limit : public T
B>>>>{
B>>>>
__>>>А почему бы не воспользоваться предикатом ? __>>>
__>>>template<typename T, T t_min, T t_max, typename TPred = std::less<T> >
__>>>class limit_t
__>>>// : public T - лучше сделать не наследование, а аггрегацию, чтобы была возможность использовать простой тип, IMHO
__>>>{
__>>> T t;
__>>>public:
__>>> //...
__>>> inline T& data() { return t; }
__>>> template< class V > inline self_t operator = (V v)
__>>> {
__>>> if( TPred(v, t_min)
__>>> throw std::out_of_range("new value not in the range - less than minimum");
__>>> if( TPred(t_max, v)
__>>> throw std::out_of_range("new value not in the range - more than maximum");
__>>> data() = v;
__>>> return *this;
__>>> }
__>>>};
__>>>
B>>для простых типов должна использоваться насадка auto_value, так что не вижу никаких препятствий для наследования. Что же касается параметризирования, то как сказано выше, атрибуты могут вкладываться один в другой, и тогда проблематично будет с этим:
__>Наверное в большинстве случаев будут использоваться простые типы, а так для них придется еще использовать дополнительный класс. __>А вообще можно сделать два класса, с наследованием и без
B>>
B>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>Здесь вы говорите обратное от того что сказано вами выше
Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру...
__>P.S. __>В вашем коде есть небольшой недочет, а имено : __>
__>Что будет если не выбрать не 5000, а 4999 ? __>Ничего
__>Так что нужна проверка для этого.
Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
B>>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>>Здесь вы говорите обратное от того что сказано вами выше B>Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
B>для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру...
Например для представления числа от 0 до 100, и есть задача чтобы все 3 цифры были, т.е. 001, 002...
__>>P.S. __>>В вашем коде есть небольшой недочет, а имено : __>>
__>>Что будет если не выбрать не 5000, а 4999 ? __>>Ничего
__>>Так что нужна проверка для этого.
B>Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке.
А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
B>>>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>>>Здесь вы говорите обратное от того что сказано вами выше B>>Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>>>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
B>>для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру... __>Например для представления числа от 0 до 100, и есть задача чтобы все 3 цифры были, т.е. 001, 002...
Ну это вряд ли, форматирование строки для представления даты скорее бы подошло, но это уже не лимит.
__>>>P.S. __>>>В вашем коде есть небольшой недочет, а имено : __>>>
__>>>Что будет если не выбрать не 5000, а 4999 ? __>>>Ничего
__>>>Так что нужна проверка для этого.
B>>Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке. __>А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
Да запросто:
в класс auto_value добавить в паблик следующую строку:
enum {def_value = i}; // где i это шаблонный параметр значения по умолчанию
в класс limit добавить следующее:
#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT( min <= T::def_value );
BOOST_STATIC_ASSERT( max >= T::def_value );
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
B>>>>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>>>>Здесь вы говорите обратное от того что сказано вами выше B>>>Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>>>>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
B>>>для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру... __>>Например для представления числа от 0 до 100, и есть задача чтобы все 3 цифры были, т.е. 001, 002... B>Ну это вряд ли, форматирование строки для представления даты скорее бы подошло, но это уже не лимит.
Ну можно придумать использования разные и не только со строкой, получится универсальный класс для многих вещей, а то так нужен еще один класс будет для реализации какой-нибудь дополнительной идеи.
__>>>>P.S. __>>>>В вашем коде есть небольшой недочет, а имено : __>>>>
__>>>>Что будет если не выбрать не 5000, а 4999 ? __>>>>Ничего
__>>>>Так что нужна проверка для этого.
B>>>Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке. __>>А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
B>Да запросто:
B>в класс auto_value добавить в паблик следующую строку:
B>
B>enum {def_value = i}; // где i это шаблонный параметр значения по умолчанию
B>
B>в класс limit добавить следующее:
B>
B>#include <boost/static_assert.hpp>
B> BOOST_STATIC_ASSERT( min <= T::def_value );
B> BOOST_STATIC_ASSERT( max >= T::def_value );
B>
А если использовать тип где enum не помогает, например float, будет проблема.
B>>>>>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>>>>>Здесь вы говорите обратное от того что сказано вами выше B>>>>Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>>>>>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
B>>>>для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру... __>>>Например для представления числа от 0 до 100, и есть задача чтобы все 3 цифры были, т.е. 001, 002... B>>Ну это вряд ли, форматирование строки для представления даты скорее бы подошло, но это уже не лимит. __>Ну можно придумать использования разные и не только со строкой, получится универсальный класс для многих вещей, а то так нужен еще один класс будет для реализации какой-нибудь дополнительной идеи.
Дык как я погляжу не очень получается придумать, второй день уже придумываем
__>>>>>P.S. __>>>>>В вашем коде есть небольшой недочет, а имено : __>>>>>
__>>>>>Что будет если не выбрать не 5000, а 4999 ? __>>>>>Ничего
__>>>>>Так что нужна проверка для этого.
B>>>>Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке. __>>>А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
B>>Да запросто:
B>>в класс auto_value добавить в паблик следующую строку:
B>>
B>>enum {def_value = i}; // где i это шаблонный параметр значения по умолчанию
B>>
B>>в класс limit добавить следующее:
B>>
B>>#include <boost/static_assert.hpp>
B>> BOOST_STATIC_ASSERT( min <= T::def_value );
B>> BOOST_STATIC_ASSERT( max >= T::def_value );
B>>
__>А если использовать тип где enum не помогает, например float, будет проблема.
Ну ты нудник!
const static T def_value = i;// где i это шаблонный параметр значения по умолчанию
Кстати, хорошо что вспомнил, на VC7 второй темплейт параметр с float не проходит, The C++ standard does not allow floating point non-type template parameters. К барьеру, мистер Кодт!
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Здравствуйте, Batiskaf, Вы писали:
B>Здравствуйте, _nn_, Вы писали:
__>>Здравствуйте, Batiskaf, Вы писали:
B>>>Здравствуйте, _nn_, Вы писали:
__>>>>Здравствуйте, Batiskaf, Вы писали:
B>>>>>>>
B>>>>>>>лимит имеет смысл заводить для интегральных величин (какой смысл у limit_t<std::string> к примеру), так что операторов "больше/меньше" вполне достаточно. __>>>>>>Здесь вы говорите обратное от того что сказано вами выше B>>>>>Ну имелось в виду простые интегральные типы, обернутые в auto_value, смысл от этого не меняется.
__>>>>>>А вообще в любом дополнительная функциональность не помешает, кроме того смысл для limit_t<std::string> можно придумать, например для ограничения длины строки
B>>>>>для этих целей я использую not_empty_string атрибут, просто не представляю ситуацию, когда нужна строка длинной не меньше 2 символов и не больше 9 к примеру... __>>>>Например для представления числа от 0 до 100, и есть задача чтобы все 3 цифры были, т.е. 001, 002... B>>>Ну это вряд ли, форматирование строки для представления даты скорее бы подошло, но это уже не лимит. __>>Ну можно придумать использования разные и не только со строкой, получится универсальный класс для многих вещей, а то так нужен еще один класс будет для реализации какой-нибудь дополнительной идеи. B>Дык как я погляжу не очень получается придумать, второй день уже придумываем
Если долго мучаться что-нибудь получится %)
__>>>>>>P.S. __>>>>>>В вашем коде есть небольшой недочет, а имено : __>>>>>>
__>>>>>>Что будет если не выбрать не 5000, а 4999 ? __>>>>>>Ничего
__>>>>>>Так что нужна проверка для этого.
B>>>>>Я не решился в конструкторе выбрасывать исключение, да и преследовалась цель защитить бизнес логику приложения от глупого пользователся, а не от глупого программиста, который делает явную ошибку в одной строке. __>>>>А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
B>>>Да запросто:
B>>>в класс auto_value добавить в паблик следующую строку:
B>>>
B>>>enum {def_value = i}; // где i это шаблонный параметр значения по умолчанию
B>>>
B>>>в класс limit добавить следующее:
B>>>
B>>>#include <boost/static_assert.hpp>
B>>> BOOST_STATIC_ASSERT( min <= T::def_value );
B>>> BOOST_STATIC_ASSERT( max >= T::def_value );
B>>>
__>>А если использовать тип где enum не помогает, например float, будет проблема.
B>Ну ты нудник!
B>
B>const static T def_value = i;// где i это шаблонный параметр значения по умолчанию
B>
Не вижу что с T=float будет работать это
B>Кстати, хорошо что вспомнил, на VC7 второй темплейт параметр с float не проходит, The C++ standard does not allow floating point non-type template parameters. К барьеру, мистер Кодт!
Можно попробовать так : (извращение)
template<typename T, T t_value>
struct value_wrapper
{
inline static T& data()
{
static T value=t_value;
return value;
}
template<typename T2, T2 t_value2>
bool operator<(const value_wrapper<T2,t_value2>& r) const
{ return data()<r.data(); }
};
/*
Вариант №2 - Тогда не нужен вызов функции
template<typename T, T t_value>
struct value_wrapper
{
inline static T& data()
{ return value; }
template<typename T2, T2 t_value2>
bool operator<(const value_wrapper<T2,t_value2>& r) const
{ return data()<r.data(); }
private:
static const T value;
};
template<typename T, T t_value>
const T value_wrapper<T,t_value>::value = t_value;
*/template<
typename T,
typename TMin = value_wrapper<T,T()>,
typename TMax = value_wrapper<T,~T()>,
typename TLess = std::less<T> >
class limit_t
{
public:
T& data() { return static_cast<T&>(*this); }
const T& data() const { return static_cast<const T&>(*this); }
template<typename T2>
limit_t& operator=(const limit_t<T2>& r)
{
if(TLess(data(),TMin::data())
throw std::out_of_range("less than minimum");
if(TLess(TMax::data(),data())
throw std::out_of_range("more than maximum);
//...
}
};
template<
typename T,
T t_min,
T t_max,
typename TLess = std::less<T> >
class limit_t_pod : public limit_t<T,value_wrapper<T,t_min>,value_wrapper<T,t_max>,TLess>
{
//...
};
__>>>>>А если будет такая ситуация то будет плохо, все же надо как-нибудь придумать защиту.
B>>>>Да запросто:
B>>>>в класс auto_value добавить в паблик следующую строку:
B>>>>
B>>>>enum {def_value = i}; // где i это шаблонный параметр значения по умолчанию
B>>>>
B>>>>в класс limit добавить следующее:
B>>>>
B>>>>#include <boost/static_assert.hpp>
B>>>> BOOST_STATIC_ASSERT( min <= T::def_value );
B>>>> BOOST_STATIC_ASSERT( max >= T::def_value );
B>>>>
__>>>А если использовать тип где enum не помогает, например float, будет проблема.
B>>Ну ты нудник!
B>>
B>>const static T def_value = i;// где i это шаблонный параметр значения по умолчанию
B>>
__>Не вижу что с T=float будет работать это
B>>Кстати, хорошо что вспомнил, на VC7 второй темплейт параметр с float не проходит, The C++ standard does not allow floating point non-type template parameters. К барьеру, мистер Кодт!
__>Можно попробовать так : (извращение) __>[c] __>template<typename T, T t_value> __>struct value_wrapper __>{ __> inline static T& data() __> { __> static T value=t_value; __> return value; __> }
__> template<typename T2, T2 t_value2> __> bool operator<(const value_wrapper<T2,t_value2>& r) const __> { return data()<r.data(); } __>};
Ха, проблема не только в том что статическая константа только интегрального типа может быть инициализирована в объявлении класса, вещественным числом даже запараметризировать темплейт нельзя, вот попробуй свой код:
для float нужно свою специализацию auto_value ваять, что я и сказал Кодту.
Для меня же интересно несколько другое применение таких атрибутов, что бы в рантайме можно было собрать всю цепочку атрибутов, проитерировать, повызывать каждый по отдельности. Вот к примеру есть строковое поле, в которое вводится IID объекта, на него можно навесить один атрибут, контролирующий длину строки ( не менее 36 символов ) и валидность этого IID для текущей системы, типа как то так:
struct length_t : public T
{
...
template< class V > inline self_t operator = (V v)
{
if( v.length() != size )
throw std::length_error("string is too big");
data() = v;
return *this;
}
...
};
template< typename T>
struct validate_iid_t : public T
{
...
validate_iid_t () : T()
{
data()=default_iid;
}
template< class V > inline self_t operator = (V v)
{
if( !IsValidIID(v) )
throw std::invalid_iid_error("bla bla");
data() = v;
return *this;
}
...
};
и хотелось бы использовать эти атрибуты в рантайме динамически, например каждый атрибут будет имплементировать несколько виртуальных функций, Next ( для навигации и перехода к следующему атрибуту ), возможность посетить атрибут, много крутых полезных вещей можно из этого поиметь...
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
B>Ха, проблема не только в том что статическая константа только интегрального типа может быть инициализирована в объявлении класса, вещественным числом даже запараметризировать темплейт нельзя, вот попробуй свой код:
B>
B>для float нужно свою специализацию auto_value ваять, что я и сказал Кодту.
B>Для меня же интересно несколько другое применение таких атрибутов, что бы в рантайме можно было собрать всю цепочку атрибутов, проитерировать, повызывать каждый по отдельности. Вот к примеру есть строковое поле, в которое вводится IID объекта, на него можно навесить один атрибут, контролирующий длину строки ( не менее 36 символов ) и валидность этого IID для текущей системы, типа как то так:
B>
B>struct length_t : public T
B>{
B>...
B> template< class V > inline self_t operator = (V v)
B> {
B> if( v.length() != size )
B> throw std::length_error("string is too big");
B> data() = v;
B> return *this;
B> }
B>...
B>};
B>template< typename T>
B>struct validate_iid_t : public T
B>{
B>...
B> validate_iid_t () : T()
B> {
B> data()=default_iid;
B> }
B> template< class V > inline self_t operator = (V v)
B> {
B> if( !IsValidIID(v) )
B> throw std::invalid_iid_error("bla bla");
B> data() = v;
B> return *this;
B> }
B>...
B>};
B>
B>и хотелось бы использовать эти атрибуты в рантайме динамически, например каждый атрибут будет имплементировать несколько виртуальных функций, Next ( для навигации и перехода к следующему атрибуту ), возможность посетить атрибут, много крутых полезных вещей можно из этого поиметь...
Что-то я не понял вашу идею.
Можно как-нибудь более подробно ?
B>>и хотелось бы использовать эти атрибуты в рантайме динамически, например каждый атрибут будет имплементировать несколько виртуальных функций, Next ( для навигации и перехода к следующему атрибуту ), возможность посетить атрибут, много крутых полезных вещей можно из этого поиметь...
__>Что-то я не понял вашу идею. __>Можно как-нибудь более подробно ?
над одной идеей раздумываю, так вот идея в рантайме эти самые атрибуты обходить с тем что бы при автоматической генерации визуального интерфейса проинтерпретировать атрибуты во фронт сайт, тем самым схемы валидации можно указывать только один раз на уровне структуры данных, а при переносе структуры в другой базис (ведь диалог отображающий содержимое структуры Person это все тот же Person, та же модель, только выраженная другими элементами ) по возможности переносить и схему валидации. Надеюсь что выразился понятно...
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Здравствуйте, Batiskaf, Вы писали:
B>Здравствуйте, _nn_, Вы писали:
B>>>и хотелось бы использовать эти атрибуты в рантайме динамически, например каждый атрибут будет имплементировать несколько виртуальных функций, Next ( для навигации и перехода к следующему атрибуту ), возможность посетить атрибут, много крутых полезных вещей можно из этого поиметь...
__>>Что-то я не понял вашу идею. __>>Можно как-нибудь более подробно ?
B>Да это мысли в слух, вот тут http://www.rsdn.ru/Forum/Message.aspx?mid=775603
над одной идеей раздумываю, так вот идея в рантайме эти самые атрибуты обходить с тем что бы при автоматической генерации визуального интерфейса проинтерпретировать атрибуты во фронт сайт, тем самым схемы валидации можно указывать только один раз на уровне структуры данных, а при переносе структуры в другой базис (ведь диалог отображающий содержимое структуры Person это все тот же Person, та же модель, только выраженная другими элементами ) по возможности переносить и схему валидации. Надеюсь что выразился понятно...
Мы уже отошли от темы auto_value и от limit
Идею я понял, надеюсь
Вот только не представляю реализацию, и до сих пор не понял ваш код в предыдущем посте.
Здравствуйте, Olegator, Вы писали:
O>Давно хотел спросить: почему бы не переделать слегка этот класс:
<>
O>Таким образом мы получим здоровую семантику нулевого объекта (а не объекта, равного нулю). Плюс поддержку не только интегральных типов.
Класс специально был написан для того, чтобы указывать начальное значение в объявлении объекта.
Наиболее часто я им пользуюсь с булевыми переменными и различными enum-ами, реже — с целыми числами.
Для структур нет смысла делать полнофункциональный auto_value.
По-видимому, нужно вообще семейство обёрток — для интегральных, для числовых, для структур.
Здравствуйте, Кодт, Вы писали:
К>Класс специально был написан для того, чтобы указывать начальное значение в объявлении объекта. К>Наиболее часто я им пользуюсь с булевыми переменными и различными enum-ами, реже — с целыми числами.
что реально пользуешся? я думал такие приколы это все теоретические изыскания...
а как же тогда быть со специализациями типа:
template<class T> void function(T t) {
...
}
template<> void function(int t) {
...
}
...
auto_value<int, 1> val;
...
function(val); // вызовется не то, что нужно
Здравствуйте, yxiie, Вы писали:
Y>что реально пользуешся? я думал такие приколы это все теоретические изыскания...
Реально.
Y>а как же тогда быть со специализациями типа:
Если семантика специализации не отличается от семантики первичного шаблона — то будет только потеря производительности (ради чего написана специализация).
Если же нужно добиться правильной работы — пишем шлюз