В следующем коде объявлен объект wrapper<T>, который содержит movable<T>, где T является неполным типом. Деструктор movable создается таким образом, что он не может быть создан без полного знания T, но деструктор wrapper только вперед-декларирован, что означает, что его должно быть достаточно, если ~movable() создается в точке определение ~wrapper().
#include <utility>
template<class T>
struct movable {
movable() noexcept = default;
~movable() noexcept { (void) sizeof(T); }
movable(const movable&) noexcept = delete;
movable(movable &&) noexcept = default;
};
template<class T>
class wrapper {
public:
movable<T> m;
wrapper() noexcept = default;
wrapper(wrapper &&) noexcept = default;
~wrapper();
};
struct incomplete;
int main() {
/* extern */ wrapper<incomplete> original;
wrapper<incomplete> copy(std::move(original));
}
Однако wrapper() хочет создать экземпляр ~movable(). Я получаю это в случае исключения, уничтожение членов должно быть возможным, но movable() и wrapper() оба не исключают. Интересно, что конструктор перемещения работает нормально (попробуйте раскомментировать часть extern в примере кода.)
В чем причина такого поведения, и есть ли способ обойти его?