Ошибка в конструкторе копирования

166
14 марта 2019, 08:00

Есть следующий упрощённый класс:

struct ID {
    int id;
    std::string string_id;
    template<typename String>
    explicit ID(String&& string_id) : string_id{std::forward<String>(string_id)}, id{std::stoi(string_id)} {}
    ID(const ID& other) : string_id{other.string_id}, id{std::stoi(other.string_id)} {}
};

Вроде как всё нормально, но когда пытаюсь вызвать конструктор копирования, получаю непонятные ошибки из explicit конструктора... В чём проблема?

ID id1("3x5");
ID id2(id1); // ошибка
Answer 1

Тут целая россыпь ошибок:

  • параметр функции string_id имеет то же имя, что и поле класса, это чревато адской путанницей
  • при передаче универсальной ссылки std::forward(string_id) пропущен параметр шаблона String
  • поля класса в списке инициализации указаны не в том порядке, в котором они будут инициализироваться
  • в записи ID id2(id1); будет более предпочтителен конструктор с универсальной ссылкой, а не копирующий (так как он принимает ID &), для исправления достаточно сделать кастование ID id2(::std::as_const(id1)); или доработать конструктор с универсальной ссылкой использую что-нибудь вроде safe_overload
Answer 2

Во-первых, std::forward требует явного указания шаблонного аргумента

string_id{std::forward<String>(string_id)}

Каким образом у вас получилось "все нормально" без вызова конструктора копирования - не ясно.

Во-вторых, ваша универсальная ссылка - "идеальный параметр", который в процессе overload resolution побеждает даже вариант с const ID& из-за необходимости квалификационного преобразования (добавления const) в последнем. Если вы в своем конструкторе копирования уберете const

ID(ID& other)

то "победит" именно он. А так - побеждает ваш

template<typename String> explicit ID(String&& string_id) 

который в таком случае получается некорректным.

READ ALSO
Плагин для nanoCad 10.0 plus x64 используя QT

Плагин для nanoCad 10.0 plus x64 используя QT

Стоит задача написать простой плагин для этой САПР системы используя инструменты NRX и фреймворк QTВ процессе работы возникла проблема, которую...

169
Практические примеры использования Windows RPC

Практические примеры использования Windows RPC

Скажите, существуют ли серьезные проекты, где в "чистом" виде используется Windows RPC для реализации клиент-серверного взаимодействия? Поиск...

133
Вызов LPSolver из приложения на C++

Вызов LPSolver из приложения на C++

Скажите, пожалуйста, как из gui приложения на C++ вызвать LPSolver? Можно пример кода?

136
Почему компилятор не ловит ошибку при неправильной работе с динамической переменной

Почему компилятор не ловит ошибку при неправильной работе с динамической переменной

Компилятор не ловит ошибку, потому что такой цели перед ним не ставитсяДля тех, кто может не сразу видит проблему в коде, поясню

154