从 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) 


我对@9​​87654325@ 一点也不满意。我必须以一定的大小实例化,才能知道size_type。对于std::array,我可以使用size_t,但是一般情况呢?如果size_type 不是size_t 怎么办?或者更一般(即不适用于std::array)如果size_type 对不同的大小不同(愚蠢但可能)怎么办?

我知道这个问题相当学术,有很多方法可以完全避免这个“问题”(例如,我可以通过迭代器)。无论如何,我想知道...

对于需要实例化 sizesize_type 类型)的模板,确定 size_type 的简洁方法是什么?

更一般地,问题可以表述为:在实际实例化模板之前,如何获得可能依赖于模板参数的模板 typedef。

【问题讨论】:

std::array&lt;T,N&gt;::size_type 不表示N 的类型,始终是std::size_t @Caleth 是的,我知道,但我需要选择一些N 才能获得std::array&lt;T,N&gt;::size_type,这就是我想要避免的。一般来说some_template&lt;N&gt;::some_typedef 可能取决于N 的值(如果std::array::size_type 是这种情况,那真的很愚蠢,但通常你永远不知道......) 即使在一般情况下,Ntype 也不依赖于 some_template&lt;N&gt;instantiation 的任何部分,因为它是some_template 声明的一部分 @Caleth 也许这个问题是基于一种误解,即std::array::size_type 的目的是获得std::arraysize_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&lt;T,N&gt;::size_type 不表示N、that's always std::size_t 的类型。

template <class T, size_t N> struct array

即使在一般情况下,N 的类型也不依赖于 some_template&lt;N&gt; 实例化的任何部分,因为它是 some_template 声明的一部分。

【讨论】:

以上是关于从 std::array 等获取 size_type 的惯用方法的主要内容,如果未能解决你的问题,请参考以下文章

为啥我可以从 初始化常规数组,而不是 std::array

string.size()和size_type

如何从方法返回静态 const int std::array?

size_type 中迭代器之间的长度

初始化 std::array 的 std::array

使用 boost::asio read_some() 函数时替代 std::array,boost::array 在 read_some() 函数调用时崩溃