Występuje błąd kompilatora, którego nie mogę wyjaśnić i nie udało mi się znaleźć informacji o nim w trybie online. Ostatnio dodałem specyfikator noexcept
do destruktora klasy opakowującej, a teraz nie można skompilować dużej liczby klas dziedziczących po klasach korzystających z tego opakowania. Próbowałem go z GCC 4.9 bez błędu kompilatora.C2694 na destruktorze, gdy destruktor elementu członkowskiego klasy podstawowej zawiera niepustujący specyfikator wyjątków noexcept i ciało
Używam Visual Studio 2015 Profesjonalna wersja 14.0.25431.01 Update 3
Rozważmy następujący minimalny kod, który reprodukuje problem:
#include <type_traits>
template<class T>
struct member
{
~member() noexcept(std::is_nothrow_destructible<T>::value) {};
};
struct parent
{
virtual ~parent() noexcept = default;
};
struct derived : public parent
{
member<int> x;
};
Fragment wytwarza się następujący komunikat o błędzie:
1>c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(19): error C2694: 'derived::~derived(void) noexcept(<expr>)': overriding virtual function has less restrictive exception specification than base class virtual member function 'parent::~parent(void) noexcept'
1> c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(19): note: compiler has generated 'derived::~derived' here
1> c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(12): note: see declaration of 'parent::~parent'
Co jest dla mnie interesujące to, że błąd kompilatora zniknął, jeśli zastąpiono ciało destruktora członka przez = default
lub użyć noexcept
lub noexcept(true)
:
// None of these produce compiler errors
virtual ~member() noexcept(std::is_nothrow_destructible<T>::value) = default;
virtual ~member() noexcept(true) {}
virtual ~member() noexcept {}
wiem, że to jest destruktor nie rzucać. Paranoids i sceptycy (jak ja) może dodać następujący statyczny assert i sprawdza się:
static_assert(std::is_nothrow_destructible<T>::value, "Might throw!");
According to MSDN sygnalizuje niewystarczającą dynamikę specyfikatora wyjątku. Jak to się tutaj stosuje? Czy nie ma żadnego wyjątku ([wyrażenie logiczne]) równoważnego z noexcept(true)
lub noexcept(false)
? Dlaczego zmienia się to w zależności od obecności ciała funkcyjnego? Dodanie jawnego noexcept destructor do wyprowadzonego powoduje błąd kompilatora, ale wydaje się to niepotrzebnym obejściem. W praktyce jest to również duże obciążenie, gdy weźmie się pod uwagę, że każda klasa pochodna musiałaby zostać zaktualizowana.
Niech upvotes mówią same za siebie, ale to jest świetne pytanie. Dziękuję i powodzenia – Tas
Fwiw, oprócz gcc 4.9, to również przechodzi przez zbiórki przez clang 3.8 w języku C++ 14 bez żadnych problemów. – WhozCraig
Wygląda jak błąd kompilatora. –