This is a retelling of my previous post, since I changed the question (so it probably didn't get flagged as a new question and was missed). I'll hopefully trim it down too.
I had functions like:
#include <cstddef>
#include <type_traits>
template < typename E, typename T >
inline constexpr
auto checked_slice( E &&, T &&t ) noexcept -> T &&
{ return static_cast<T &&>(t); }
template < typename E, typename T, std::size_t N, typename U, typename ...V >
inline constexpr
auto checked_slice( E &&e, T (&t)[N], U &&u, V &&...v )
-> typename remove_some_extents<T, sizeof...(V)>::type &
{
typedef typename std::remove_reference<U>::type u_type;
typedef typename std::common_type<u_type, std::size_t>::type cmp_type;
return ( u < u_type{} ) || ( static_cast<cmp_type>(u) >=
static_cast<cmp_type>(N) ) ? throw e : checked_slice( static_cast<E &&>(e),
t[static_cast<U &&>( u )], static_cast<V &&>(v)... );
}
where remove_some_extents
is a custom class template that's like calling the std::remove_extent
meta-function a given number of times.
When I tried running the program, I got a bunch of errors like: "invalid initialization of reference of type Whatever(&)[X][Y]
from expression of type Whatever(*)[Y]
" (or Whatever(&)[Z]
from Whatever*
). My workaround was to convert the conditional expression to an if
-else
pair (and removing the constexpr
).
I'm trying to figure out what's wrong, so I'm poking around the section about the conditional operator in the C++ (2011) standard. That's section 5.16. When one of the two possible actions is a throw command (or is otherwise a void
expression), then the conditional has the type of the other expression, but the standard conversions, including array-to-pointer, is applied to that other expression. (This is in paragraph 2.) I think that's what's messing me up. Is there any way around it? I thought returning an array reference suppresses the a-to-p conversion. Why does it work when made into an if/else
?