1. C++ / Говнокод #12587

    +24

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    template <typename IdType, class Tag>
    class id {
    public:
        typedef IdType value_type;
    
        explicit id(value_type val)
            : value(val)
        {}
    
        bool operator==(id rhs)
        {
            return rhs.value == value;
        }
    
        bool operator!=(id rhs)
        {
            return rhs.value != value;
        }
    
        value_type value;
    };
    
    #define HASKELL_NEWTYPE(type_name, value_type) struct __##type_name##_tag__ {}; \
        typedef ::id<value_type, __##type_name##_tag__> type_name

    Когда newtype нет, но очень хочется.
    http://ideone.com/VRu56j
    Простите за синтетику

    Запостил: roman-kashitsyn, 14 Февраля 2013

    Комментарии (21) RSS

    • операторы зачем неконстантные?
      Ответить
      • Да, спасибо за поправку. Это только демонстрация, писалось в порыве вдохновения.
        Ответить
        • никогда такого нужно не было
          ну и в реализации явно есть проблемы
          http://ideone.com/BEBK7Z
          Ответить
          • >Когда newtype нет, но очень хочется.
            >никогда такого нужно не было
            не сошлись во мнениях.
            Почему данные public? И проверку неравенства может надо через проверку равенства, не?
            Ответить
    • Типичное кресторешение всех проблем шаблонами и препроцессором.
      Не пойму - какой от этого профит?
      Ответить
      • Пресловутые типобезопасность и инкапсуляция. Чтобы id, который по сути является числом, нельзя было заменить этим самым числом, сравнивать напрямую с числом (только id с id). Т.е. чтобы, например, id одной модели нельзя было сравнивать или случайно спутать с id другой модели.

        Конкретно в текущем проекте нам это могло бы пригодится, ибо много числовых идентификаторов, которые иногда путаются друг с другом.
        @Yuuri по этому поводу вздыхал по хаскелевским newtype, за пять минут было придумано решение. Но, думаю, профит от этого не превышает возникающих проблем, внедрять не будем, разумеется.
        Ответить
        • Не проще ле использовать User Defined Literals (C++11)
          Ответить
          • нет, тут как раз им нужен с++11 class enum
            Ответить
            • Нет, там нужны были именно физически несовместимые числовые типы. Как вышеупомянутый хаскельный newtype или же typedef в D.
              Ответить
              • Я вот такую херню юзал:
                template <class IdType, class Type>
                class unique_id : public boost::noncopyable
                {
                public:
                    unique_id() : id(next_id()) {
                    }
                    friend std::ostream & operator << (std::ostream &stream, const unique_id &u) {
                        return stream << u.id;
                    }
                    bool operator == (const unique_id &other) const {
                        return id == other.id;
                    }
                    bool operator != (const unique_id &other) const {
                        return id != other.id;
                    }
                private:
                    IdType id;
                    static IdType next_id() {
                        static boost::atomic<IdType> next_id(0);
                        return next_id.fetch_add(1, boost::memory_order_relaxed);
                    }
                };
                
                class foo {
                private:
                    unique_id<uint32_t, foo> id;
                };
                Ответить
                • По-хорошему boost::noncopyable там нахуй не нужен, но я тогда почему-то об этом не подумал. А == и != вообще не юзаются (да и как их поюзаешь с noncopyable), ибо эти unique_id использовались только для логирования. Так что будем считать это очередным говнокодом ;)
                  Ответить
                • Вот как-то так я бы это переделал, чтобы эти айдишки можно было юзать в мапах и прочих структурах, но влом коммитить, раз работает...
                  template <class IdType, class Type>
                  class unique_id
                  {
                  public:
                      unique_id() : id(next_id()) {
                      }
                      unique_id(const unique_id &other) : id(other.id) {
                      }
                      explicit unique_id(const IdType &value) : id(value) {
                      }
                      friend std::ostream & operator << (std::ostream &stream, const unique_id &u) {
                          return stream << u.id;
                      }
                      bool operator == (const unique_id &other) const {
                          return id == other.id;
                      }
                      bool operator != (const unique_id &other) const {
                          return id != other.id;
                      }
                  private:
                      IdType id;
                      static IdType next_id() {
                          static boost::atomic<IdType> next_id(0);
                          return next_id.fetch_add(1, boost::memory_order_relaxed);
                      }
                  };
                  Ответить
                  • На самом деле это не совсем то, что нужно. К тому же, тут в одном классе замешаны две концепции - абстракция идентификатора и метод генерации идентификаторов.
                    Нам было нужно что-то вроде
                    template <typename ModelType,
                              typename ReprType = unsigned long>
                    class id_of {
                    public:
                        typedef ModelType model_type;
                        typedef ReprType repr_type;
                    
                        id_of()
                            : id_()
                        {}
                    
                        explicit id_of(repr_type id)
                            : id_(id)
                        {}
                    
                        repr_type value() const {
                            return id_;
                        }
                    
                        bool operator==(const id_of & rhs) const {
                            return value() == rhs.value();
                        }
                    
                        bool operator!=(const id_of & rhs) const {
                            return value() != rhs.value();
                        }
                    
                        bool operator<(const id_of & rhs) const {
                            return value() < rhs.value();
                        }
                    
                        bool operator>(const id_of & rhs) const {
                            return value() > rhs.value();
                        }
                    
                    private:
                        repr_type id_;
                    };
                    
                    id_of<widget> x{5};
                    id_of<gadget> y{5};
                    // x == y <- compile error
                    Ответить
                    • Ну у меня цель немного другая была - выводить айдишки channel'ов и request'ов в лог. Поэтому и noncopyable и генерация были сдуру прикручены к этому unique_id.

                      А так - согласен, генератор лучше отдельный сделать.
                      Ответить
                    • Как-то так, наверное:
                      template <class Unique>
                      Unique next_unique_id()
                      {
                          static boost::atomic<typename Unique::repr_type> next_id(0);
                          return Unique(next_id.fetch_add(1, boost::memory_order_relaxed));
                      }
                      
                      typedef id_of<widget> widget_id;
                      
                      widget_id x(next_unique_id<widget_id>());
                      Ответить
                      • Постойте, но ведь генератор айдишников - это нестабильный инпут-итератор.
                        Ответить
          • Точно,
            object_id oid = 0_o;
            Ответить
      • Кстати, вроде как оверхеда во время выполнения не будет, размер алиаса будет идентичен размеру типа, который заалиасили, а операции заинлайнятся (ну вылитый newtype).
        К сожалению, макрос, как правильно указал @defecate-plusplus, страдает от непреодолимых (?) преблем для типов в неймспесах или шаблонных типов.
        Ответить
    • BOOST_STRONG_TYPEDEF
      http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/strong_typedef.html
      Ответить
      • И откопал же.
        Перечитал тред: то ли сон клонит, то ли от плотность крестоблядства на один пост, но аж голова кругом идёт.
        Ответить

    Добавить комментарий