> why the replacement of return types in the original code presented here does not work
> when replaced with 'decltype(auto)'?
> My interpretation was that C++ 14 would always be able to deduce the return type
> and that using decltype(auto) would also do that and preserve the referenceness of the return type.
The deduced return type would require that the template is instantiated; therefore, on line 15, the unary overload of
has_const_reference_op<T,E>::test must be instantiated. At this point,
has_const_reference_op<T,E> is an incomplete type and compilers are unhappy because the nested instantiation of a template (in an unevaluated context) involves an incomplete type. Caveat: AFAIK.
If there is no demand for the nested instantiation of a member of an incomplete type, deduced return type via
decltype(auto) would be fine. For instance:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
template< typename T > struct is_const_dereferencible
{
template< typename U > static
decltype(auto) test( const U&& u, typename std::remove_reference< decltype( *u ) >::type* = nullptr ) { return std::true_type() ; }
static decltype(auto) test(...) { return std::false_type{} ; }
using type = decltype( test( std::declval< typename std::decay<T>::type >() ) ) ;
static constexpr bool value = type::value ;
};
template< typename T, typename = void >
struct const_dereferenced_type { struct nothing ; using type = nothing ; using base_type = nothing ; } ;
template< typename T >
struct const_dereferenced_type< T, typename std::enable_if< is_const_dereferencible<T>::value >::type >
{
using type = decltype( *std::declval< typename std::add_const< typename std::decay<T>::type >::type >() ) ;
using base_type = typename std::decay<type>::type ;
};
template< typename T, typename E > struct has_const_reference_op :
std::conditional< is_const_dereferencible<T>::value &&
std::is_same< typename const_dereferenced_type<T>::type, E >::value,
std::true_type, std::false_type >::type {};
|
http://coliru.stacked-crooked.com/a/a3b62f832effe46b
In any case, the original code, even without the deduced return type, is broken.
When a class has an overloaded
operator*(), it selects the wrong (non const) overload.
http://coliru.stacked-crooked.com/a/1ecf07efb84fae63
http://rextester.com/NCEW16517