如何才能使一个可变参数根据链索引功能? [英] How can one make a variadic-based chained-indexing function?

查看:184
本文介绍了如何才能使一个可变参数根据链索引功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个对象 A ,无论是内置阵列或一个类类型与合适的运算符[] ,它的返回类型可以被索引本身,我应该怎么写一个通用的功能,可以索引所有的人都具有可变参数调用,而不是分开的支架块?换句话说,我可以让前pressions这样的:

If I have an object a that either a built-in array or a class-type with a suitable operator [], and its returned type can be indexed itself, how should I write a generic function that can index all of them with a variadic call instead of separated bracket block? In other words, I can make expressions like:

a[i0][i1]...[iK]

和我希望能够把它写成一个单一的功能:

and I want to be able to write it as a single function:

slice( a, i0, i1, ..., iK )

由于C ++的需要规则运算符[] 来单参数的工作,使得有可变参数的东西不那么兼容。 (这个问题是基于一个新闻线索,我试着问类似的东西;结束了解决只可能嵌套内置阵列我自己)

since the rules of C++ require operator [] to work on single arguments, making it less-compatible with variadic stuff. (This question is based on a Usenet thread where I tried asking something similar; ending up solving only possibly-nested built-in arrays myself.)

第一刺:

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 -marked 的std ::前进。 (在标准有些东西可能被标记 constexpr 都没有。)我试图找出正确的东西放在返回类型和异常规范斑点。有些病例和警告我所知道的是:

The ce_forward function templates are a constexpr-marked std::forward. (Some things in the standard that could be marked constexpr aren't.) I'm trying to figure out the right stuff to put in the return type and exception specification spots. Some cases and caveats I know of are:


  • 内置运算符[] 需要一个操作数是一个数据指针(或腐烂数组引用),另一个是一个枚举或整数类型。操作数可以是任意顺序。我不知道,如果操作数可以与一个类类型具有明确的(非明示?)转换到一个适当的类型替换。

  • 类类型可以定义运算符[] 非静态成员函数(S)。任何这样的功能只能有一个参数(除了这个)。

  • 内置运营商不能扔。 (除非操作数可以基于一个UDT转换;所述转换是唯一可能的抛出点。)引起的边界错误的未定义的行为超出了我们的职权范围此处

  • 不管最后的索引调用返回一个L值参考,R值的参考,或值应的返回类型有所体现。

  • 如果(最终?)调用是值,则的std :: is_nothrow_move_constructible&LT;返回类型&GT; ::值应OR操作的异常规范。 (通过参考收益 noexcept

  • 如果内置的运营商涉及一个数组,该步骤返回的引用应该是R值的参考,如果数组是一太。 (这是一种-的缺陷,因为指针与数组不同,失去目标的1-与R值的状态,所以传统的回报将永远是一个L值的参考。)

  • 对于类类型的索引操作,确认异常规范并返回类型的段指的是相同的过载(如果有多个),该函数体使用。警惕仅在资格上不同的重载这个常量 / 挥发性 /都/既不和/或&安培; / &放大器;&安培; /既不)

  • The built-in operator [] requires one operand to be a data-pointer (or decayed array reference) and the other to be an enumeration or integer type. The operands can be in either order. I don't know if an operand could be replaced with a class-type with an unambiguous (non-explicit?) conversion to an appropriate type.
  • A class type can define operator [] as non-static member function(s). Any such function can only have one parameter (besides this).
  • The built-in operator can't throw. (Unless operands could be based on an UDT conversion; said conversion is the only possible throw point.) The undefined behavior caused by boundary errors is beyond our purview here.
  • Whether the last indexing call returns a l-value reference, r-value reference, or value should be reflected in the return type of slice.
  • If the (final?) call is by-value, then std::is_nothrow_move_constructible<ReturnType>::value should be OR'd to the exception specification. (By-reference returns are noexcept.)
  • If the built-in operator involves an array, the returned reference for that step should be a r-value reference if the array is one too. (This is kind-of a defect because pointers, unlike arrays, lose their target's l- vs. r-value status, so the traditional return would always be a l-value reference.)
  • For class-type indexing operators, make sure the exception-spec and return-type sections refer to the same overload (if more than one) that the function body uses. Be wary for overloads that differ only in the qualification of this (const/volatile/both/neither and/or &/&&/neither).

推荐答案

我想出了一个解决方案,基于@吕克 - 丹东和答复的评论@ user315052。

I've come up with a solution, based on the comment by @luc-danton and answer by @user315052.

#include <utility>

template < typename Base, typename ...Indices >
class indexing_result;

template < typename T >
class indexing_result<T>
{
public:
    using type = T;

    static constexpr
    bool  can_throw = false;
};

template < typename T, typename U, typename ...V >
class indexing_result<T, U, V...>
{
    using direct_type = decltype( std::declval<T>()[std::declval<U>()] );
    using   next_type = indexing_result<direct_type, V...>;

    static constexpr
    bool  direct_can_throw
     = not noexcept( std::declval<T>()[std::declval<U>()] );

public:
    using type = typename next_type::type;

    static constexpr
    bool  can_throw = direct_can_throw || next_type::can_throw;
};

template < typename T >
inline constexpr
auto  slice( T &&t ) noexcept -> T &&
{ return static_cast<T &&>(t); }

template < typename T, typename U, typename ...V >
inline constexpr
auto  slice( T &&t, U &&u, V &&...v )
  noexcept( !indexing_result<T, U, V...>::can_throw )
  -> typename indexing_result<T, U, V...>::type
{
    return slice( static_cast<T &&>(t)[static_cast<U &&>( u )],
     static_cast<V &&>(v)... );
}

我把完整的例子计划成一个要点。它的工作在一个网站上运行的编译器GCC> = 4.7,铛> = 3.2,而Intel C ++> = 13.0。

I put a full example program up as a Gist. It worked on a web-site compiler running GCC >= 4.7, CLang >= 3.2, and Intel C++ >= 13.0.

这篇关于如何才能使一个可变参数根据链索引功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆