Ho creato un header for optionally-lazy parameters (visibile anche in un GitHub repository). (Questo è not my first question based on the header.)Il distruttore virtuale modifica il comportamento di decltype
Ho un modello di classe base e due modelli di classe derivata. Il modello di classe base ha un costruttore protected
con un static_assert
. Questo costruttore è chiamato solo da una particolare classe derivata. All'interno del static_assert
sto usando un decltype
.
La cosa veramente strana è che il tipo di un nome all'interno del decltype
è in qualche modo influenzata dalla presenza o meno di un distruttore virtuale nel mio modello di base di classe.
Ecco la mia 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;}));
}
Nota che se il distruttore è commentata, questo viene compilato senza errori.
L'intento è per callable
di essere un'espressione di tipo U
che, quando viene chiamato con l'operatore ()
, restituisce qualcosa di tipo T
. Senza il distruttore virtuale in Base
, sembra che questo sia stato valutato correttamente; con il distruttore virtuale, sembra che il tipo callabele
sia Base<T>
(che, per quanto posso dire, non ha senso).
Ecco G ++ messaggio di errore 5.1 del:
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
Ecco Clang ++ messaggio di errore 3.7 del:
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 il costruttore di copia anche attiva questo errore.
non ho potuto dirvi sull'errore distruttore virtuale strano, ma vedo che 'Derivato (U && callable)' accetta un valore di R riferimento e non un riferimento universale. È destinato? – SirGuy
Potresti aggiungere qualche output all'esempio che mostra cosa dovrebbe fare. TakesWrappedInt sembra ottenere uno zero con il tuo esempio, a causa dell'operatore finale T() ;. –
@GuyGreer No, non è previsto. È perché, una volta specializzato il modello, U non è più un tipo di modello? –