Здесь задействовано несколько ошибок, см. https://bugs.llvm.org/show_bug.cgi?id=39363#c8
Итак: две ошибки в GCC (хотя они могут быть одинаковыми), одна ошибка в поддержке Clang C ++ 17, однаошибка в libstdc ++, и никаких ошибок в libc ++.Ретаргетинг это как ошибка Clang.:)
И libstdc ++ фактически был дефектом в стандарте, который был непреднамеренно исправлен с помощью https://wg21.link/lwg2081 (подробности см. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87704).
Я думаю, что программа в действительности недопустима в режиме C ++ 14, потому что инициализатор члена по умолчанию использует инициализацию копирования, поэтому создается временный объект, затем перемещается из него, а затем временный уничтожается.Уничтожение временного означает, что деструктор должен быть создан, что требует полного типа.В режиме C ++ 17 гарантированное исключение копирования означает, что временного нет, и, следовательно, нет экземпляра деструктора, и код должен быть действительным.Но GCC и Clang делают неправильно, даже в режиме C ++ 17.
Если вы используете прямую инициализацию списка вместо инициализации копирования, тогда она работает с Clang:
std::unique_ptr<Impl> ptr{nullptr};
И это также работает:
std::unique_ptr<Impl> ptr{};
И эквивалент:
std::unique_ptr<Impl> ptr = {};
И просто не предоставляя инициализатор вообще также работает, и работает с GCC тоже:
std::unique_ptr<Impl> ptr;