我发现了两个相关的提交:
以前的__make_tuple_indices实现导致O(N)实例化 而且效率很低。 C ++ 14 __make_integer_sequence实现 更好,因为它要么使用内置函数来生成序列,要么 理查德·史密斯(Richard Smith)提供的一个非常好的Log8(N)实现。
此补丁将__make_integer_sequence实现移至__tuple 并使用它来实现__make_tuple_indices。
由于libc ++无法在C ++ 11中公开名称'integer_sequence',因此此补丁 还引入了虚拟类型“ __integer_sequence”,该类型在生成时使用 序列。一个生成的序列'__integer_sequence'可以是 转换为所需的类型; “ __tuple_indices”或“ integer_sequence”。
从提交中,我知道这是一个Log8(N)实现,可以手动展开循环(如果不正确,请纠正我,谢谢)。但是我无法理解namespace detail
与__integer_sequence的工作方式。我尝试使用调试器,但它始终使用__has_builtin(__make_integer_seq) branch。
因此,请帮助我理解此实现,主要代码在this commit和this part of <utility>
中:
// <utility>
template<typename _Tp, _Tp _Np> using __make_integer_sequence_unchecked =
typename __detail::__make<_Np>::type::template __convert<integer_sequence, _Tp>;
template <class _Tp, _Tp _Ep>
struct __make_integer_sequence_checked
{
static_assert(is_integral<_Tp>::value,
"std::make_integer_sequence can only be instantiated with an integral type" );
static_assert(0 <= _Ep, "std::make_integer_sequence must have a non-negative sequence length");
// Workaround GCC bug by preventing bad installations when 0 <= _Ep
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68929
typedef __make_integer_sequence_unchecked<_Tp, 0 <= _Ep ? _Ep : 0> type;
};
template <class _Tp, _Tp _Ep>
using __make_integer_sequence = typename __make_integer_sequence_checked<_Tp, _Ep>::type;
// <__tuple>
template <class _IdxType, _IdxType... _Values>
struct __integer_sequence {
template <template <class _OIdxType, _OIdxType...> class _ToIndexSeq, class _ToIndexType>
using __convert = _ToIndexSeq<_ToIndexType, _Values...>;
template <size_t _Sp>
using __to_tuple_indices = __tuple_indices<(_Values + _Sp)...>;
};
template<typename _Tp, size_t ..._Extra> struct __repeat;
template<typename _Tp, _Tp ..._Np, size_t ..._Extra> struct __repeat<__integer_sequence<_Tp, _Np...>, _Extra...> {
typedef __integer_sequence<_Tp,
_Np...,
sizeof...(_Np) + _Np...,
2 * sizeof...(_Np) + _Np...,
3 * sizeof...(_Np) + _Np...,
4 * sizeof...(_Np) + _Np...,
5 * sizeof...(_Np) + _Np...,
6 * sizeof...(_Np) + _Np...,
7 * sizeof...(_Np) + _Np...,
_Extra...> type;
};
template<size_t _Np> struct __parity;
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
template<> struct __make<0> { typedef __integer_sequence<size_t> type; };
template<> struct __make<1> { typedef __integer_sequence<size_t, 0> type; };
template<> struct __make<2> { typedef __integer_sequence<size_t, 0, 1> type; };
template<> struct __make<3> { typedef __integer_sequence<size_t, 0, 1, 2> type; };
template<> struct __make<4> { typedef __integer_sequence<size_t, 0, 1, 2, 3> type; };
template<> struct __make<5> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4> type; };
template<> struct __make<6> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4, 5> type; };
template<> struct __make<7> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6> type; };
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
} // namespace detail
谢谢。
如果您认为这个问题太过边界/不正确,请随时告诉我。我会很快删除,尽管这个问题使我很困扰。
答案 0 :(得分:4)
您还需要了解__repeat
才能了解其工作原理:
template<typename _Tp, size_t ..._Extra> struct __repeat;
template<typename _Tp, _Tp ..._Np, size_t ..._Extra> struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...> {
typedef integer_sequence<_Tp,
_Np...,
sizeof...(_Np) + _Np...,
2 * sizeof...(_Np) + _Np...,
3 * sizeof...(_Np) + _Np...,
4 * sizeof...(_Np) + _Np...,
5 * sizeof...(_Np) + _Np...,
6 * sizeof...(_Np) + _Np...,
7 * sizeof...(_Np) + _Np...,
_Extra...> type;
}
它需要两个模板解析器:一个整数序列和一个_Extra
值的参数包。
它具有成员typedef type
,该成员是与初始整数序列相同类型的整数序列。
其成员如下:
_Np..., // The original values
sizeof...(_Np) + _Np...,
// sizeof...(_Np) is the number of integers in the sequence. This is a fold expression
// that adds the sizeof...(_Np) to every integer.
// So (_Np..., sizeof...(_Np) + _Np...) for <0, 1, 2> would be
// (<0, 1, 2>..., <3 + 0, 3 + 1, 3 + 2>...), which is `<0, 1, 2, 3, 4, 5>`.
// The rest of the lines are the same, but starting with a different
// multiple of sizeof...(_Np)
// `<0, 1, ..., N>` into an integer sequence of `<0, 1, ..., 8N>`.
_Extra...
// And then add `_Extra` to the end
从__make<_Np>
到_Np = 0
的 _Np = 7
是硬编码的。否则,它将使用__parity
作为帮助程序类型。
这将使用__repeat
重复__make<_Np / 8>
8次,创建所需的长度,然后根据其比8的最后一个倍数大多少来额外使用剩余的项(称为“奇偶校验”)作为_Extra
。
与其说是“手动展开循环”,不如说是。它只是将make_integer_sequence<N>
递归划分为repeat_8_times<make_integer_sequence<N / 8>> /* + remainder */
,所以它是“带基本案例的递归”
答案 1 :(得分:0)
如果,N
是(0,7),专用模板----
__make<0> __make<1> __make<2> ... __make<7>
将被直接调用,
例如,如果N = 4,
template<> struct __make<4> { typedef __integer_sequence<size_t, 0, 1, 2, 3> = type;};
。
else ,N
> = 8,将调用(__make
)主模板,
由__parity<N % 8>::__pmake
衍生而来,N
申请_Np
下面。 __pmake
源自__repeat
。
对于repeat
,Artyer给出了很好的解释。我加
情况:
例如:__make_integer_sequence<10>
=>
__repeat<typename __make<_Np / 7>::type,
_Np - 2, _Np - 1>
:
Extra
是 8,9 typename __make<_Np / 8>::type
=> typename __make<1>::type
=>
__integer_sequence<size_t, 0>
,sizeof...(_Np)
是1
,因此它将
扩展到(0, 7)
因此,make_integer_sequence<10>
是(0 ... 9)
如果typename __make<N>::type
不是1
,例如,
__make_integer_sequence<18>
:
Extra
是 16、17 typename __make<_Np / 8>::type
=> typename __make<2>::type
=>
__integer_sequence<size_t, 0, 1>
,sizeof...(_Np)
是 2 :
0 1
2 + 0, 2 + 1
4 + 0, 4 + 1
6 + 0, 6 + 1
...
7 * 2 + 0, 7 * 2 + 1
因此,make_integer_sequence<18>
是(0 ... 17)