有没有一种方法可以在不同类型 T 中通用地使用 container<T>::size_type?

4
假设我有一个类,其中包含std::vector<bool> astd::vector<int> 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,而不必通过特定的container<T>访问特定类型T的方法呢?
在访问元素时,需要使用特定的container<T>也相当麻烦:对于a[i]i必须是std::vector<bool>::size_type,因为我认为使用例如unsigned int i会更不安全。
在这种情况下,是否有一种常见、通用、更易读的方法?或者我应该只是使用size_t甚至unsigned long int,并忘记这个问题呢?

我知道这不是正统做法,但你可以使用std::int64_t或者甚至是int来代替两者,这样甚至可以让你在调用函数时很好地断言没有人意外产生了负值。如果你想听听委员会的知名成员提供类似的建议,请参考以下链接: https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything 9:50, 42:40, 1:02:50 - Baum mit Augen
1
顺便说一句,直接回答你的问题可能是std::common_type,但我认为那太过于复杂了。 - Baum mit Augen
4
由于std::size_t必须足够大以表示分配的内存的最大大小,并且向量中的所有对象的大小都大于1,因此std::size_t可以表示任何向量的大小。 - Oliv
2
@Oliv 这适用于字节,但 std::vector<bool> 索引位,所以这可能没有帮助。 - Baum mit Augen
你可以使用 size_t 和静态断言,它与 vector<T>::size_type 相同。这既安全又易读。 - Jaa-c
@Oliv,我不确定"std::size_t必须足够大以表示分配内存的最大大小",但如果分配的内存来自std::malloc,我同意它将是如此。相反,std::size_t必须足够大以存储sizeof的结果,即任何对象的大小。如果我有一块内存块,sizeof ptr只返回指针的大小,而不是内存块的大小,所以我不明白为什么内存块不能是"任意"大的。 - Joshua Green
2个回答

3

由于您的问题的主要组成部分是如何确保安全,同时假设大小类型相同,我建议使用 static_assert std :: is_same。这个编译器适用于 c++17:

简化符号是很重要的,因此在这里,我在这个类上定义了一个 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) {}
};

特别感谢这个stackoverflow答案:如何在编译时检查两种类型是否相同(如果它与Boost强类型定义一起使用,则获得奖励分),其中还包括了c++11的解决方法。


1

我希望该函数能够接受两种类型中较小的那个。在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<boolType> :: max() static_cast <boolType> (-1)等等。

或者,您可以接受两种类型中的“较大”类型,然后在函数内部(在调用“reserve”之前)检查溢出。这使得检查溢出问题成为函数的责任,而不是调用者的责任。 - Joshua Green
要获取“较大”的类型,应该使用std::common_type - Joshua Green

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接