从 std::array 等获取 size_type 的惯用方法
Posted
技术标签:
【中文标题】从 std::array 等获取 size_type 的惯用方法【英文标题】:Idiomatic way to get size_type from std::array or the like 【发布时间】:2019-12-27 12:18:32 【问题描述】:由this question 触发,我想出了以下代码(在我的答案中是boost::array
,但同样适用于std::array
):
template <std::array<char,1>::size_type size>
void DataTransform(std::array<char, size> data)
我对@987654325@ 一点也不满意。我必须以一定的大小实例化,才能知道size_type
。对于std::array
,我可以使用size_t
,但是一般情况呢?如果size_type
不是size_t
怎么办?或者更一般(即不适用于std::array
)如果size_type
对不同的大小不同(愚蠢但可能)怎么办?
我知道这个问题相当学术,有很多方法可以完全避免这个“问题”(例如,我可以通过迭代器)。无论如何,我想知道...
对于需要实例化 size
(size_type
类型)的模板,确定 size_type
的简洁方法是什么?
更一般地,问题可以表述为:在实际实例化模板之前,如何获得可能依赖于模板参数的模板 typedef。
【问题讨论】:
std::array<T,N>::size_type
不表示N
的类型,始终是std::size_t
@Caleth 是的,我知道,但我需要选择一些N
才能获得std::array<T,N>::size_type
,这就是我想要避免的。一般来说some_template<N>::some_typedef
可能取决于N
的值(如果std::array::size_type
是这种情况,那真的很愚蠢,但通常你永远不知道......)
即使在一般情况下,N
的 type 也不依赖于 some_template<N>
的 instantiation 的任何部分,因为它是some_template
声明的一部分
@Caleth 也许这个问题是基于一种误解,即std::array::size_type
的目的是获得std::array
的size_type
,而实际上这根本不需要。也许array::size_type
更适合在您有一个未知类型的实例化容器时使用...
@Caleth 啊,好的,现在我明白你想说的话了。呃,似乎我真的想多了这个问题。然而,答案显示了在更一般的场景中可能有用的方法
【参考方案1】:
这是一个 C++11 解决方案,它采用未推导的数组,然后在默认模板参数中提取涉及的类型和大小,最后执行 enable_if
来检查我们是否确实得到了 std::array
:
#include <array>
#include <type_traits>
template<
class TArray,
class TSize = typename TArray::size_type,
class TValue = typename TArray::value_type,
TSize size = std::tuple_size<TArray>::value>
typename std::enable_if<std::is_same<std::array<TValue, size>, TArray>::value>::type
DataTransform(TArray data)
// Enjoy!
https://godbolt.org/z/KMziYq
通过默认模板参数执行所有这些操作意味着这是 SFINAE 友好的(所有检查都在替换期间完成)。但与 C++17 解决方案相比,它也相当拗口 :)
我应该提到std::tuple_size
(与原始问题基本相同)确实完全使用std::size_t
。这应该不是问题,因为std::size_t
应该能够保存所有相关值,我们仍然提取并提供上面的“正确”TSize
。但是你可以在没有std::tuple_size
的情况下完成所有这一切,只需编写自己的TSize
并仅推导出大小值:
template<class TValue, class TSize, class T>
struct MyTupleSize;
template<class TValue, class TSize, TSize size>
struct MyTupleSize<TValue, TSize, std::array<TValue, size>>
static constexpr TSize value = size;
;
https://godbolt.org/z/zlseRm
【讨论】:
@StoryTeller 如果std::array
没有提供类型定义,那么这确实是不可能的,我相信。【参考方案2】:
纯粹的 C++17 解决方案是回避这个问题:
template <auto size>
void DataTransform(std::array<char, size> data)
推导出size
的类型。然后,如果您需要以某种方式使用该类型,只需在函数模板中应用 decltype(size)
。
【讨论】:
我仍然坚持使用 C++11,但由于这个问题主要是出于好奇,我很乐意接受 C++17 的答案 @foreknownas_463035818 - 我不相信所需的机器存在于 C++17 之前。但如果有人证明我在这方面错了,我会很兴奋。 很抱歉,由于我的思路出现了一些错误,被 Caleth 发现,我不得不接受不同的答案。我认为重新提出这个问题没有意义,但我只会接受这个问题的正确答案,恕我直言,其他答案仍然是非常有价值的贡献【参考方案3】:您始终可以使用模板使用的特定类型。
std::array<T,N>::size_type
不表示N
、that's always std::size_t
的类型。
template <class T, size_t N> struct array
即使在一般情况下,N
的类型也不依赖于 some_template<N>
实例化的任何部分,因为它是 some_template
声明的一部分。
【讨论】:
以上是关于从 std::array 等获取 size_type 的惯用方法的主要内容,如果未能解决你的问题,请参考以下文章
如何从方法返回静态 const int std::array?
使用 boost::asio read_some() 函数时替代 std::array,boost::array 在 read_some() 函数调用时崩溃