• Как поместить "нетривиальный" объект в стуктуру?

    @Mercury13
    Программист на «си с крестами» и не только
    Одно из полей (в данном случае data в реализации item<Edge>) не имеет конструктора по умолчанию. Есть три пути.

    РАЗ. Придумать, как сделать, чтобы конструктор всё-таки был.
    class Edge : public EdgeBase
    {
    public:
      Edge (Point* firstPoint, Point* secondPoint) { init(firstPoint, secondPoint); }
      Edge () { init(NULL, NULL); }
      void init (Point* firstPoint, Point* secondPoint)
      {
        this->firstPoint = firstPoint;
        this->secondPoint = secondPoint;
      }
    private:
      Point* firstPoint;
      Point* secondPoint;
    };


    ДВА. Если объект копируется/переносится, можно воспользоваться такой штукой. С вашего позволения, упрощу задачу и вместо Edge заведу другой класс — ImmutableInt. Правда, этот код — попытка совместить ежа с ужом (непонятно, какую концепцию должен поддерживать Payload), но, тем не менее, работает.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next;
    
        ListItem() : next(NULL) {}
        ListItem(const Payload& x) : payload(x), next(NULL) {}
    };
    
    // Так писать нельзя — эта конструкция расшаблонивает все функции,
    // а конструктора по умолчанию как не было, так и нет!
    //template class ListItem<ImmutableInt>;
    
    int main()
    {
        ListItem<ImmutableInt> li(ImmutableInt(42));
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    ТРИ. Воспользоваться переменными шаблонами (variadic templates) C++11.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next = nullptr;
    
        template<class... Args>ListItem(Args... args) : payload(args...) {}
    };
    
    int main()
    {
        ListItem<ImmutableInt> li(42);
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    P.S. Хотя ImmutableInt — семантически тот же int и теоретически explicit не надо, всё-таки отметил — просто чтобы показать, что во втором случае мы передаём параметром ImmutableInt<42>, а в третьем — 42.

    P.P.S. Я упомянул слово «концепция». Это набор требований к типу. Что-то типа интерфейса — но, во-первых, никак не связано с ООП и его динамическим полиморфизмом, и, во-вторых, не столь жёсткое: как ты интерфейсом из Java наладишь концепцию «есть конструктор копирования» или «может делить себя на число и что-то выходит»? Синтаксическая поддержка концепций откладывается на C++17, но уже в C++03 было несколько концепций: InputIterator, DefaultConstructible, CopyAssignable и другие. А пока… концепция не поддерживается — ошибка компиляции где-то в страшенном стандартном хедере.

    P.P.P.S. Написав код
    template<typename type_t>
    struct item
    {
      item* next;
      type_t data;
    };

    вы автоматически потребовали от type_t концепцию DefaultConstructible (есть конструктор по умолчанию)
    Ответ написан
    1 комментарий
  • Почему перезаписываются данные в структуре?

    mbeloshitsky
    @mbeloshitsky
    Вебдев, систем оперейшонс, ж.д. автоматика
    Вы же выделяете массив, поэтому по-моему здесь нужен указатель на указатель:

    int allocate_lines(struct line** lines, int Number)
    {
      lines* = (line*)malloc(Number*sizeof(struct line));
      if (!lines)
      {
        return CANT_ALLOCATE_LINES;
      }
      return OK;
    }
    ...
    struct line * lines;
    error = allocate_lines(&lines, View.Model.Edge.Number);
    Ответ написан
    1 комментарий