【发布时间】:2012-04-16 09:20:44
【问题描述】:
如果我有一个对象a 是一个内置数组或具有合适operator [] 的类类型,并且它的返回类型可以自己索引,我应该如何编写一个可以索引所有的通用函数其中有一个可变参数调用而不是分隔的括号块?换句话说,我可以表达如下:
a[i0][i1]...[iK]
我希望能够将其编写为单个函数:
slice( a, i0, i1, ..., iK )
因为 C++ 的规则要求 operator [] 处理单个参数,这使得它与可变参数的东西不太兼容。 (这个问题基于一个 Usenet 线程,我在其中尝试过类似的问题;最终我自己只解决了可能嵌套的内置数组。)
第一刀:
template < typename T, typename U >
constexpr
auto slice( T &&t, U &&u ) noexcept(???) -> ???
{ return ce_forward<T>(t)[ ce_forward<U>(u) ]; }
template < typename T, typename U, typename V, typename ...W >
constexpr
auto slice( T &&t, U &&u, V &&v, W... &&w ) noexcept(???) -> ???
{
return slice( ce_forward<T>(t)[ce_forward<U>(u)], ce_forward<V>(v),
ce_forward<W>(w)... );
}
ce_forward 函数模板是一个constexpr 标记的std::forward。 (标准中可以标记为constexpr 的一些东西不是。)我试图找出正确的东西来放入返回类型和异常规范点。我知道的一些案例和注意事项是:
- 内置
operator []要求一个操作数是数据指针(或衰减数组引用),另一个是枚举或整数类型。操作数可以是任意顺序。我不知道是否可以将操作数替换为具有明确(非显式?)转换为适当类型的类类型。 - 类类型可以将
operator []定义为非静态成员函数。任何此类函数只能有一个参数(this除外)。 - 内置运算符不能抛出。 (除非操作数可以基于 UDT 转换;所述转换是唯一可能的抛出点。)由边界错误引起的未定义行为超出了我们的权限范围。
- 最后一次索引调用返回左值引用、右值引用还是值应该反映在
slice的返回类型中。 - 如果(最终?)调用是按值调用,则应将
std::is_nothrow_move_constructible<ReturnType>::value与异常规范进行“或”运算。 (按引用返回是noexcept。) - 如果内置运算符涉及数组,则该步骤的返回引用应该是 r 值引用(如果数组也是 1)。 (这是一种缺陷,因为与数组不同,指针会丢失其目标的左值与右值状态,因此传统的返回始终是左值引用。)
- 对于类类型索引运算符,请确保异常规范和返回类型部分引用函数体使用的相同重载(如果有多个)。请注意仅在
this的限定条件上有所不同的重载(const/volatile/both/neither 和/或&/&&/neither)。
【问题讨论】:
-
对于我使用它的目的,它应该尽可能是
constexpr。 -
您是否考虑过简单地将与
return语句中相同的表达式用于返回类型和noexcept规范?例如。noexcept(noexcept(std::declval<T>()[std::declval<U>()])) -> decltype(std::declval<T>()[std::declval<U>()]).