w128
w128

Reputation: 4928

Is there a way to use container<T>::size_type universally for different types T?

Suppose I have a class with std::vector<bool> a and std::vector<int> b fields that I want to reserve() in a constructor to some size which is equal for both containers. Given that reserve() accepts size_type parameter, to be fully safe, I have to - from what I understand - write my constructor using two parameters, which is not particularly appealing:

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);
}

From what I've read, size_type is usually the same as size_t, at least for standard containers, so I could probably do this without ever encountering any potential problems:

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

However, is there a better, safer way to strictly use size_type without having to access it via a specific container<T> for a specific type T?

Having to use a specific container<T> is also rather annoying when e.g. accessing an element: for a[i], i has to be std::vector<bool>::size_type, as I assume that using e.g. unsigned int i would be less safe.

Is there a common, universal, more readable way to go in such situations? Or should I simply use size_t or even unsigned long int and forget about this?

Upvotes: 4

Views: 172

Answers (2)

Joshua Green
Joshua Green

Reputation: 1575

I'd have the function accept the smaller of the two types. In C++11, this can be done via:

#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)
{...}

Lacking C++11, you can manually define your own version of std::conditional and replace std::numeric_limits<boolType>::max() with static_cast<boolType>(-1), etc..

Upvotes: 1

Kenny Ostrom
Kenny Ostrom

Reputation: 5871

Since the primary component of your question is how do you ensure your safety while just assuming the size types are the same, I would recommend static_assert std::is_same. This compiles with c++17:

Simplifying the notation was important, so here, I typedef a size_type on this class, and internally make sure it is the same as both of the size types it is representing. If they don't match, it is a compile time error.

#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) {}
};

Special thanks to this stack overflow answer: How to check if two types are same at compiletime(bonus points if it works with Boost strong typedef) which also includes the c++11 workaround.

Upvotes: 3

Related Questions