Vorac Vorac - 4 months ago 14
C++ Question

How to detect if a container is guaranteed to have sequence storage

Checking if a sequence container is contiguous in memory.

C++ templates that accept only certain types

I am writing a simple

send()
method, which internally works with C-style pointers. I would like it to be able to work with all the guaranteed sequence containers. My motivation being twofold:


  • a flexible interface

  • efficiency - using
    std::array
    avoids heap allocations.



Here is how far I am:

template <typename Container>
void poll( Container &out )
{
static_assert( std::is_base_of< std::array<typename Container::value_type>, Container >::value ||
std::is_base_of< std::vector<typename Container::value_type>, Container >::value ||
std::is_base_of< std::string<typename Container::value_type>, Container >::value,
"A contiguous memory container is required.");
}


Trouble is,
std::array
requires a second parameter, and that cannot be known at compile time. Is this problem solvable? Possibly by a different approach?

Answer

The right way here is to use a trait class. std::is_base_of is a kind of trait. Basically: You have a templated struct that takes a (template) param and returns its result via a nested type/value.

In your case something like this

template<typename T>
struct HasContiguousStorage: public std::false_type{};

template<typename T>
struct HasContiguousStorage<std::vector<T>>: public std::true_type{};
// Specialize others

As you should not derive from standard containers, this should be enough. This can also check for the array:

template<typename T, size_t N>
struct HasContiguousStorage<std::array<T,N>>: public std::true_type{};

In your function you can then either overload it (see enable_if) or branch on it (branch will be evaluated at compile-time)