3

这是对我之前帖子的复述,因为我更改了问题(因此它可能没有被标记为新问题而被遗漏)。我也希望把它剪下来。

我有这样的功能:

#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)... );
}

whereremove_some_extents是一个自定义类模板,就像调用std::remove_extent元函数给定次数一样。

当我尝试运行该程序时,我遇到了一堆错误,例如:“从类型Whatever(&)[X][Y]的表达式中对类型的引用进行无效初始化Whatever(*)[Y]”(或Whatever(&)[Z]Whatever*)。我的解决方法是将条件表达式转换为if-else对(并删除constexpr)。

我试图找出问题所在,所以我在 C++ (2011) 标准中关于条件运算符的部分进行了讨论。这是第 5.16 节。当两个可能的操作之一是 throw 命令(或者是void表达式)时,条件具有另一个表达式的类型,但标准转换(包括数组到指针)将应用于该另一个表达式。(这在第 2 段中。)我认为这让我很困惑。有什么办法吗?我认为返回数组引用会抑制 a-to-p 转换。为什么它在制成时起作用if/else

4

1 回答 1

4

你的分析是正确的。我怀疑非void操作数在这种情况下会“衰减”(即执行通常的转换),以便模仿两个操作数类型不同时发生的情况——在后一种情况下,往往不是整个条件表达式是prvalue。

我们确定条件表达式的值类别和类型的一种情况是两个操作数完全匹配时,因此我们可以利用它来发挥我们的优势:

cond ? (throw e, t) : t

将是数组引用类型的左值。(当然最后一个操作数不一定是字面意思t——你可以在这里插入你的递归调用。)

if使用/时您没有遇到任何此类障碍,else因为作为语句,语言不必为其指定通用类型和值类别。

于 2013-04-27T00:52:56.800 回答