Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Как инициализировать объект через список инициализации

#cpp #cpp11 #инициализация


Есть такой класс:

class Book {
public:
    char* name;
    char** authors;
    int authorsCount;
    int publishingYear;
    Book(const char* name_,\
         const char* authors[],\
         int authorsCount_, \
         int publishingYear_);
    bool operator < (const Book &other) const;
    void print(void) const;
    ~Book();
};


Как правильно(и возможно ли вообще) инициализировать объект этого класса используя
список инициализации(Braced initialization)? Вот такой вариант почему-то не работает:

Book b = {"Skazki", {"Ivanov", "Petrov"}, 2, 1968};



  error: could not convert ‘{"Skazki", {"Ivanov", "Petrov"}, 2, 1968}’
  from ‘’ to ‘Book’
       Book b = {"Skazki", {"Ivanov", "Petrov"}, 2, 1968};

    


Ответы

Ответ 1



Вы пытаетесь инициализировать указатель const char **authors при помощи инициализатора {"Ivanov", "Petrov"}. Компилятору, разумеется, совершенно не ясно, что вы пытаетесь сделать. Конструировать в такой ситуации временный массив язык не будет. Чтобы в такой ситуации заставить компилятор сконструировать временный объект типа массив из {}-инициализатора, придется явно указать перед ним имя "массивного" типа. При этом "сложные" имена типов в таком контексте неупотребимы, т.е. придется сначала завернуть тип массив в компактное typedef-имя, например так using A = const char *[]; Book b = {"Skazki", A{"Ivanov", "Petrov"}, 2, 1968}; Если бы у вас в конструкторе был параметр типа const char* const (&authors)[2] то компилятор бы самостоятельно расценил ваше {"Ivanov", "Petrov"} как инициализатор для временного массива типа const char *[2]. Но вам этот вариант не подходит, ибо в вашем случае размер массива является значением времени выполнения. Что интересно, GCC не хочет компилировать и вариант с A{"Ivanov", "Petrov"}, ибо не разрешает брать адрес временного массива. Причины такого запрета не ясны. Вроде в стандарте его навскидку не видно. И Clang успешно компилирует этот вариант.

Ответ 2



Во-первых следует изменить поля класса чтобы они могли хранить передаваемые таким образом данные. Указатели char * должны быть const char * (или string_view) так как они указывают на неизменяемые массивы со статическим временем жизни полученные из строковых литералов. Указать char * * должен стать контейнером, так как передаваемый массив в любом случае будет временным, а нужно, чтобы он жил на протяжении жизни создаваемого объекта. private: using Authors = ::std::vector; private: char const * m_name; private: Authors m_authors; private: int m_publishingYear; public: explicit Book ( char const * const name , ::std::initializer_list const authors , int const publishingYear ) : m_name{name} , m_authors{authors} , m_publishingYear{publishingYear} {} Book b{"Skazki", {"Ivanov", "Petrov"}, 1968}; Online compiler

Комментариев нет:

Отправить комментарий