I created a header for optionally lazy parameters (also visible on GitHub repository). (This is not my first title based question .)
I have a base class template and two derived class templates. The base class template has a protected constructor with static_assert . This constructor is called only by a specific derived class. Inside static_assert I use decltype .
It is really strange that the type of the name inside decltype somehow depends on whether a virtual destructor exists in my base class template.
Here is my 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;})); }
Note that if the destructor is commented out, it compiles without errors.
The goal of callable is an expression of type U , which when called with the operator () returns something of type T Without a virtual destructor in Base , it seems like this is being evaluated correctly; with a virtual destructor, it seems that the type of callabele is Base<T> (which, as far as I can tell, does not make sense).
Here's the g ++ 5.1 error message:
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
Here is the Clang ++ 3.7 error message:
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.
Here is the online version.
EDIT: =delete -repeat the copy constructor also causes this error.
c ++ templates c ++ 14 decltype virtual-destructor
Kyle strand
source share