SRC: auto_value<>
От: Кодт Россия  
Дата: 16.01.03 12:10
Оценка: 207 (25) +1
Вот, достало ловить ошибки с неинициализованными членами больших классов, вида
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, а не 0xCDCDCDCD
  void setEnabled(bool b) { m_bEnabled = b; }
  ...
};
Перекуём баги на фичи!
Re: SRC: auto_value<>
От: comer США http://getboost.codeplex.com/
Дата: 16.01.03 12:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
...
К>  inline operator T  () const { return t_; }
...
К>


Может лучше будет?
inline operator T const &() const { return t_; }


К>  // операторы присваивания

А как же все остальные? сравнение, сложение, сдвиги, инкрементация и т.п. и т.д.?
getboost.codeplex.com
citylizard.codeplex.com
Re[2]: SRC: auto_value<>
От: Atilla Россия  
Дата: 16.01.03 12:42
Оценка:
Здравствуйте, comer, Вы писали:

C>А как же все остальные? сравнение, сложение, сдвиги, инкрементация и т.п. и т.д.?


это для простеньких-то типов (int, char, void*) ?
... << RSDN@Home 1.0 beta 4 >>
Кр-ть — с.т.
Re[2]: SRC: auto_value<>
От: Кодт Россия  
Дата: 16.01.03 13:07
Оценка: +1
Здравствуйте, comer, Вы писали:

К>>  inline operator T  () const { return t_; }


C>Может лучше будет?

C>inline operator T const &() const { return t_; }

Заведомо не лучше. Невозможно будет использовать неявное преобразование типов.
Больше того, даже форма
  inline operator const T& () const { return t_; }

приведет к неоднозначности и куче матов со стороны компилятора (проверял на VC 6sp5, GCC 2.7.2).

C>
К>>  // операторы присваивания
C>

C>А как же все остальные? сравнение, сложение, сдвиги, инкрементация и т.п. и т.д.?

Если определен operator T() const
то нужда у них отпадает.

Про инкремент — да, забыл.
Добавляю
  inline self_t operator ++ ()    { ++t_; return *this; } // префиксный
  inline data_t operator ++ (int) { return t_++; } // постфиксный

аналогично — для декремента.
Перекуём баги на фичи!
Re: SRC: auto_value<>
От: Кодт Россия  
Дата: 16.01.03 18:14
Оценка:
Дополнение
К>template< class T, T i = 0 >
К>class auto_value


Обычное применение этого шаблона — простые типы, передаваемые по значению. Поэтому параметр "i" оставлен того же типа, что и поле данных.

Однако, если есть большая нужда в приведении типов, то легко расширить шаблон:
template< class T, class I = T, I i = 0 >
class auto_value_ex
{
  .....
};


Если определить auto_value через auto_value_ex,
template< class T, T i = 0 >
class auto_value : public auto_value_ex< T, T, i >
{
  .....
};

то придется затащить в него все конструкторы и, вероятно, операторы. Поменяется шило на мыло.
Перекуём баги на фичи!
Re[3]: SRC: auto_value<>
От: comer США http://getboost.codeplex.com/
Дата: 16.01.03 18:18
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
C>>inline operator T const &() const { return t_; }
К>

К>Заведомо не лучше. Невозможно будет использовать неявное преобразование типов.

Проверял на GCC 3.1. Там все нормально. Проходит без ругательств. В том числе и неявное преобразование типов с операторами возвращающими ссылку на константу. Вообще то я не совсем понимаю, почему не проходит неявное преобразование с ссылками на константы, а с обычными проходит? Приведи пример, пожалуйста. Просто я стараюсь делать как можно более похожие интерфейсы функций/операторов для константного и неконстантного объекта. Привычка.

К>Если определен operator T() const

К>то нужда у них отпадает.
Угу. Сорри.
getboost.codeplex.com
citylizard.codeplex.com
Re[3]: SRC: auto_value<>
От: comer США http://getboost.codeplex.com/
Дата: 16.01.03 18:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
C>>inline operator T const &() const { return t_; }
К>

К>Заведомо не лучше. Невозможно будет использовать неявное преобразование типов.

И еще. Вот с таким оператором,
operator T const &() const;


можно написать так:
auto_value<int, 3> const a;
int const &b = a;


С таким
operator T() const;


уже так не напишешь.
getboost.codeplex.com
citylizard.codeplex.com
Re[3]: SRC: auto_value<>
От: comer США http://getboost.codeplex.com/
Дата: 16.01.03 18:35
Оценка:
Здравствуйте, Atilla, Вы писали:

C>>А как же все остальные? сравнение, сложение, сдвиги, инкрементация и т.п. и т.д.?

A>это для простеньких-то типов (int, char, void*) ?
А зачем их дискриминировать? Чем они хуже?
getboost.codeplex.com
citylizard.codeplex.com
Re[4]: SRC: auto_value<>
От: Кодт Россия  
Дата: 16.01.03 18:47
Оценка:
Здравствуйте, comer, Вы писали:

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
      ...
  }
  ...
};

а если — как
operator T() const
, то не имеем.

Впрочем, можно определить оба варианта:
  operator T () const { return t_; }
  operator const T& () const { return t_; }
  operator T& () { return t_; }

(может быть, где-то в другом месте вылезет ambiguous call).
А пока я добавил эту тулзу вот с этими тремя операторами в большой проект, и надеюсь поиметь отзывы от сотрудников в течение недели.
Перекуём баги на фичи!
Re[5]: SRC: auto_value<>
От: comer США http://getboost.codeplex.com/
Дата: 16.01.03 19:29
Оценка:
Здравствуйте, Кодт, Вы писали:


К>У меня тоже эта привычка. Однако такой пример:

К>
К>...
К>    if( !m_bEnabled )
К>...
К>

Как обычно, во всем виноват MS. GCC 3.1 нормально компилирует нечто подобное.

К>Впрочем, можно определить оба варианта:

К>
К>  operator T () const { return t_; }
К>  operator const T& () const { return t_; }
К>  operator T& () { return t_; }
К>

К>(может быть, где-то в другом месте вылезет ambiguous call).
К>А пока я добавил эту тулзу вот с этими тремя операторами в большой проект, и надеюсь поиметь отзывы от сотрудников в течение недели.

Кстати, если объявлены два таких оператора
inline operator T const &() const { return t_; }
inline operator T () const { return t_; }

то GCC 3.1, не может откомпилировать вот это:

auto_value<bool> b;
!b;

Если только один любой из них, то может.

Так что:
    inline operator T const &() const { return t_; }
#ifdef _MSC_VER 
    inline operator T() const { return t_; }  
#endif


Интересно, кстати, какой из этих операторов в таком случае будет использовать VC?
getboost.codeplex.com
citylizard.codeplex.com
Re[6]: SRC: auto_value<>
От: Кодт Россия  
Дата: 16.01.03 19:38
Оценка:
Здравствуйте, 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.
Перекуём баги на фичи!
Re[2]: SRC: auto_value<>
От: Andrew S Россия http://alchemy-lab.com
Дата: 16.01.03 22:33
Оценка:
Возможно, я скажу глупость, но я бы использовал template < class T, T i = T() >
что дает таки большую свободу в типах, нежели инициализирование нулем.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: SRC: auto_value<>
От: MaximE Великобритания  
Дата: 16.01.03 22:47
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
К>  // доступ к данному
К>  inline const T& data() const { return t_; }
К>


Саттер и ISO/IEC 14882 пишут, что функция вида:
T f();

где T является встроенным типом, всегда возвращает r-value. cv-квалифиатор не может быть применен к r-value, и это может помешать инстанцированию шаблонов.
Т.е., чтобы это было совсем корректно, возможно, придется воспользоваться type traits.
Re[2]: SRC: auto_value<>
От: Кодт Россия  
Дата: 17.01.03 08:43
Оценка:
Здравствуйте, 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 (и в дальнейшем, например, использовать указатель на константу:
auto_value<int> x;

const int *y = & x.data();
Перекуём баги на фичи!
Re[3]: SRC: auto_pod<>
От: Кодт Россия  
Дата: 17.01.03 08:54
Оценка:
Здравствуйте, 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).
Перекуём баги на фичи!
Re[4]: SRC: auto_pod<>
От: Andrew S Россия http://alchemy-lab.com
Дата: 17.01.03 08:58
Оценка:
К>Вопрос: int() == 0?

Как я помню — да. Значение по умолчанию для int — 0. запись вида int i = int(); инициализирует переменную значением по умолчанию.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: SRC: auto_value<>
От: MaximE Великобритания  
Дата: 17.01.03 09:20
Оценка:
Здравствуйте, Кодт, Вы писали:

К>И именно поэтому я пишу не T data() const, а const T& data() const.

К>Чтобы получить константное l-value (и в дальнейшем, например, использовать указатель на константу:

Простите, облажался я . Не заметил &
Re[4]: SRC: auto_pod<>
От: Блудов Павел Россия  
Дата: 27.01.03 06:52
Оценка: 42 (1)
Здравствуйте, Кодт, Вы писали:

К>(тут нужно быть аккуратным с пустыми структурами, т.к. их sizeof() == 1).


Этот вопрос решается простым наследованием структуры с одним полем байтовой длины:

#define _offsetof(type, field)    ((int)&((type*)0)->field)

template< class POD >
struct auto_pod : public POD
{
  struct _PODSize : POD { char _Dummy; };

  auto_pod() { memset( static_cast<POD*>(this), 0, _offsetof(_PODSize, _PODSize::_Dummy)); }
};


Если POD без полей, то 1 == sizeof(POD), и 0 == _offsetof(_PODSize, _PODSize::_Dummy).

Интересный, кстати момент:

struct aa
{
    __int64    i1;
    __int8    i2;
};

16 == sizeof(aa);


Хотя в этом случае, нилем имеет смысл прописать только первые 9-ть байт.
Есть идеи?

Павел.
Re[5]: SRC: auto_pod<>
От: Кодт Россия  
Дата: 27.01.03 09:22
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

К>>(тут нужно быть аккуратным с пустыми структурами, т.к. их sizeof() == 1).


БП>Этот вопрос решается простым наследованием структуры с одним полем байтовой длины:


Супер!
БП>#define _offsetof(type, field)    ((int)&((type*)0)->field)

БП>template< class POD >
БП>struct auto_pod : public POD
БП>{
БП>  struct _PODSize : POD { char _Dummy; };

     inline static size_t sizeofpod() { return _offsetof(_PODSize, _PODSize::_Dummy); }

БП>  auto_pod() { memset( static_cast<POD*>(this), 0, sizeofpod()); }

     auto_pod(const POD& pod) { memcpy( static_cast<POD*>(this), &pod, sizeofpod() ); }

     void operator=(const POD& pod) { memcpy( static_cast<POD*>(this), &pod, sizeofpod() ); }
БП>};


БП>Если 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
{ };


БП>Интересный, кстати момент:


БП>
БП>struct aa
БП>{
БП>    __int64    i1;
БП>    __int8    i2;
БП>};

БП>16 == sizeof(aa);
БП>


БП>Хотя в этом случае, нилем имеет смысл прописать только первые 9-ть байт.

БП>Есть идеи?

А пусть компилятор сам занимается этим. Он оптимизировал размер, пусть он же оптимизирует копирование.

(И вообще, memset/memcpy/memmove — это моветон. Проблема-то была — объехать баг VC).
Перекуём баги на фичи!
Re[6]: SRC: auto_pod<>
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 09.02.03 10:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Супер!

#define _offsetof(type, field)    ((int)&((type*)0)->field)

Такой код может быть написан только в реализации стандартной библиотеки, или в компиляторно-зависимой библиотеке. Для всего остального разыменование нулевого указателя не является легальным C++ (p->m => (*(p)).m (см. 5.2.5/3)).

Ну, и про идентификаторы тоже... Все, что начинается с _<Большая латинская> — зарезервировано.
Алексей Кирдин
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.