这是对my previous post的重述,因为我改变了问题(所以它可能没有被标记为新问题而被遗漏)。我也希望能减少它。
我的功能如下:
#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)... );
}
其中remove_some_extents
是一个自定义类模板,就像调用std::remove_extent
元函数一样。
当我尝试运行该程序时,我遇到了一堆错误,例如:“类型Whatever(&)[X][Y]
的类型Whatever(*)[Y]
的引用无效初始化”(或来自{{Whatever(&)[Z]
的{{1}} 1}})。我的解决方法是将条件表达式转换为Whatever*
- if
对(并删除else
)。
我正在试图弄清楚什么是错的,所以我在C ++(2011)标准中关于条件运算符的部分进行讨论。这是第5.16节。当两个可能的动作之一是throw命令(或者是constexpr
表达式)时,条件具有另一个表达式的类型,但标准转换(包括数组到指针)应用于那个别的表达。 (这是在第2段。)我认为这是弄乱我的。它有什么办法吗?我认为返回数组引用会抑制a-to-p转换。为什么在制作成void
时会起作用?
答案 0 :(得分:4)
您的分析是正确的。我怀疑在这种情况下非void
操作数是'衰减'(即通常的转换),以便模仿当两个操作数在类型上不同时会发生什么 - 在后一种情况下更多通常情况下,整个条件表达式都是prvalue。
我们确切知道条件表达式的值类别和类型的一种情况是两个操作数是完全匹配的时候,所以我们可以利用它来做到这一点:
cond ? (throw e, t) : t
将是数组引用类型的左值。 (当然最后一个操作数不一定是t
- 你可以在这里插入你的递归调用。)
使用if
/ else
时没有遇到任何此类障碍,因为语句不必为其指定常用类型和值类别。