Ich habe eine header for optionally-lazy parameters erstellt (auch sichtbar in einer GitHub repository). (Dies ist not my first question based on the header.)Virtueller Destruktor ändert Verhalten von declType
Ich habe eine Basisklasse-Vorlage und zwei abgeleitete Klassenvorlagen. Die Basisklassenvorlage hat einen protected
-Konstruktor mit einer static_assert
. Dieser Konstruktor wird nur von einer bestimmten abgeleiteten Klasse aufgerufen. Innerhalb der static_assert
benutze ich eine decltype
.
Die wirklich bizarr ist, dass die Art der einen Namen innerhalb des decltype
irgendwie durch die betroffen ist, ob es ein virtuelles destructor ist in meiner Basis-Klasse-Vorlage.
Hier ist meine MCVE:
#include <type_traits>
#include <utility>
template <typename T>
class Base
{
protected:
template <typename U>
Base(U&& callable)
{
static_assert(
std::is_same<
typename std::remove_reference<decltype(callable())>::type, T
>::value,
"Expression does not evaluate to correct type!");
}
public:
virtual ~Base(void) =default; // Causes error
virtual operator T(void) =0;
};
template <typename T, typename U>
class Derived : public Base<T>
{
public:
Derived(U&& callable) : Base<T>{std::forward<U>(callable)} {}
operator T(void) override final
{
return {};
}
};
void TakesWrappedInt(Base<int>&&) {}
template <typename U>
auto MakeLazyInt(U&& callable)
{
return Derived<
typename std::remove_reference<decltype(callable())>::type, U>{
std::forward<U>(callable)};
}
int main()
{
TakesWrappedInt(MakeLazyInt([&](){return 3;}));
}
Beachten Sie, dass, wenn die destructor Kommentar gesetzt ist, dies ohne Fehler kompiliert wird.
Die Absicht ist für callable
ein Ausdruck des Typs zu sein U
, die, wenn sie mit dem ()
Operator genannt, T
etwas vom Typ zurückgibt. Ohne den virtuellen Destruktor in Base
scheint es, dass dies richtig ausgewertet wird; mit der virtuelle Destruktor, es scheint, dass callabele
ist der Typ Base<T>
(was, soweit ich sagen kann, keinen Sinn macht).
Hier G ++ 5.1 die Fehlermeldung:
recursive_lazy.cpp: In instantiation of ‘Base<T>::Base(U&&) [with U = Base<int>; T = int]’:
recursive_lazy.cpp:25:7: required from ‘auto MakeLazyInt(U&&) [with U = main()::<lambda()>]’
recursive_lazy.cpp:48:47: required from here
recursive_lazy.cpp:13:63: error: no match for call to ‘(Base<int>)()’
typename std::remove_reference<decltype(callable())>::type, T
Hier Clang ++ 3.7 die Fehlermeldung:
recursive_lazy.cpp:13:55: error: type 'Base<int>' does not provide a call operator
typename std::remove_reference<decltype(callable())>::type, T
^~~~~~~~
recursive_lazy.cpp:25:7: note: in instantiation of function template specialization
'Base<int>::Base<Base<int> >' requested here
class Derived : public Base<T>
^
1 error generated.
EDIT:=delete
-Ing die Kopie-Konstruktor auch löst diesen Fehler aus.
ich Sie nicht über die seltsame virtuellen Destruktor Fehler sagen könnte, aber ich sehe, dass 'Abgeleitete (U && aufrufbar)' ein r-Wert annimmt Referenz und keine universelle Referenz. Ist das beabsichtigt? – SirGuy
Könnten Sie dem Beispiel eine Ausgabe hinzufügen, die zeigt, was es tun soll? TakesWrappedInt scheint aufgrund des letzten Operators T(); in Ihrem Beispiel eine Null zu erhalten. –
@GuyGreer Nein, es ist nicht beabsichtigt. Ist dies der Fall, weil U nach der Spezialisierung der Vorlage nicht mehr ein Schablonentyp ist? –