【问题标题】:Is there a way to use container<T>::size_type universally for different types T?有没有办法将 container<T>::size_type 普遍用于不同类型的 T?
【发布时间】:2017-12-29 14:05:38
【问题描述】:

假设我有一个带有std::vector&lt;bool&gt; astd::vector&lt;int&gt; b 字段的类,我想在构造函数中将reserve() 设置为两个容器相等的大小。鉴于 reserve() 接受 size_type 参数,为了完全安全,我必须 - 据我了解 - 使用两个参数编写构造函数,这并不是特别吸引人:

MyCtor(std::vector<bool>::size_type size1, std::vector<int>::size_type size2)
{
    abortIfNotEqual(size1, size2); // Proceed only if size1 == size2
    a.reserve(size1);
    b.reserve(size2);
}

根据我的阅读,size_type通常size_t 相同,至少对于标准容器而言,所以我可以这样做而不会遇到任何潜在问题:

MyCtor(std::size_t size)
{
    a.reserve(size); // More readable, but is this always ok?
    b.reserve(size);
}

但是,有没有更好、更安全的方法来严格使用size_type,而不必通过特定类型T 的特定container&lt;T&gt; 访问它?

必须使用特定的container&lt;T&gt; 也很烦人,例如访问一个元素:对于a[i]i 必须是std::vector&lt;bool&gt;::size_type,因为我假设使用例如unsigned int i 会不太安全。

在这种情况下,是否有一种通用的、通用的、更易读的方法?还是我应该简单地使用size_t 甚至unsigned long int 而忘记这个?

【问题讨论】:

  • 我知道这不是规范,但您可以只使用std::int64_t 甚至可能同时使用int,这甚至可以让您断言没有人在调用函数时意外产生负值。如果您想听听知名委员会成员的类似建议:channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
  • 顺便说一句,您的问题的直接答案可能是std::common_type,但我再次认为这是矫枉过正。
  • 由于std::size_t 必须足够大以表示已分配内存的最大大小,并且由于向量中的所有对象的大小都大于1,因此std::size_t 可以表示任何向量的大小。
  • @Oliv 这适用于字节,但 std::vector&lt;bool&gt; 索引位,所以不需要帮助。
  • 您可以使用size_t 和静态断言,它与vector&lt;T&gt;::size_type 相同。它既安全又可读。

标签: c++ std


【解决方案1】:

由于您的问题的主要组成部分是在假设尺寸类型相同的情况下如何确保您的安全,因此我建议您使用 static_assert std::is_same。这用 c++17 编译:

简化符号很重要,所以在这里,我在这个类上 typedef 一个 size_type,并在内部确保它与它所代表的两种尺寸类型相同。如果它们不匹配,则为编译时错误。

#include <vector>

class MyCtor {
    std::vector<bool> a;
    std::vector<int> b;
    typedef std::vector<bool>::size_type st1;
    typedef std::vector<int>::size_type st2;
    static_assert(std::is_same<st1, st2>::value);
public:
    typedef st2 size_type;
    MyCtor(size_type s1, size_type s2) {}
};

特别感谢这个堆栈溢出答案:How to check if two types are same at compiletime(bonus points if it works with Boost strong typedef),其中还包括 c++11 解决方法。

【讨论】:

    【解决方案2】:

    我会让函数接受两种类型中较小的一个。在 C++11 中,这可以通过以下方式完成:

    #include <vector>
    #include <type_traits>
    #include <limits>
    
    typedef std::vector<bool>::size_type boolType;
    typedef std::vector<int>::size_type intType;
    
    typedef std::conditional<(std::numeric_limits<boolType>::max() <
                              std::numeric_limits<intType>::max()),
                             boolType,
                             intType>::type smallerSizeType;
    
    MyCtor(smallerSizeType size)
    {...}
    

    缺少C++11,可以手动定义自己的std::conditional版本,将std::numeric_limits&lt;boolType&gt;::max()替换成static_cast&lt;boolType&gt;(-1)等。

    【讨论】:

    • 或者,您可以接受这两种类型中的较大的,然后检查是否溢出(在调用reserve 之前)inside 函数。这使得检查溢出问题是函数的责任,而不是调用者的责任。
    • (要获得 更大的 类型,std::common_type 就足够了。)
    猜你喜欢
    • 1970-01-01
    • 2022-06-21
    • 2016-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多