5

I have an interface that deals with any container type. std::vector, std::array, and even std::basic_string. The issue is that there is nothing to prevent someone from passing a container that does not have continguous memory.

The current solution I have is to delete those interface I want to prevent.

void dosoemthing(const std::list&)=delete;
void dosoemthing(const std::map&)=delete;

However, I would prefer if I could just add a static assertion based on the type trait. Which leads to my question. Does their exist a type trait for containers that can be used to identify if its memory is contiguous? I have been coming through the documentation and have yet to find anything. I figured before marking it a lost cause I would check with the A team.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
Freddy
  • 2,249
  • 1
  • 22
  • 31
  • 1
    [What are the qualifications for a class in C++ to become a container?](http://stackoverflow.com/questions/33064590/what-are-the-qualifications-for-a-class-in-c-to-become-a-container) – David G Oct 11 '15 at 17:32
  • 2
    @0x499602D2 That doesn't answer the question at all. A `std::map` is a container but one of the container types the OP explicitly wants to exclude from the set of overloads because it doesn't guarantee contiguous memory. – leemes Oct 11 '15 at 18:12
  • @leemes I see. My mistake. – David G Oct 11 '15 at 18:15
  • 1
    Just for your information: it seems that C++17 will have a concept for that (Of course you still need something for C++11, but I wanted to tell you that for C++17 we probably have a standard way to check that.) – leemes Oct 11 '15 at 18:30

1 Answers1

8

You can bring your own type trait, and then use static_assert to verify it:

#include <type_traits>
#include <vector>
#include <array>

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

template<typename T, typename U>
struct has_contiguous_memory<std::vector<T, U>> : std::true_type {};

template<typename T>
struct has_contiguous_memory<std::vector<bool, T>> : std::false_type {};

template<typename T, typename U, typename V>
struct has_contiguous_memory<std::basic_string<T, U, V>> : std::true_type {};

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

template<typename T>
struct has_contiguous_memory<T[]> : std::true_type {};

template<typename T, std::size_t N>
struct has_contiguous_memory<T[N]> : std::true_type {};
Stas
  • 11,571
  • 9
  • 40
  • 58
  • I'd make the `vector` version also accept a non-default allocator (its second template argument; just add another one). Besides that, you could rewrite the last three specializations as one which accepts any container which iterator is a pointer type. That would include all three versions, but also include other containers, but maybe also potentially containers that use a pointer type for the iterator but don't guarantee contiguous memory? (I'm not sure if the last is true) – leemes Oct 11 '15 at 18:19
  • @leemes Good point, thanks! I've just fixed specialization for `std::vector`. Concerning the latter: I would keep existing checks, because they are more explicit. – Stas Oct 11 '15 at 18:27
  • Yeah it probably is the better way. Also, I couldn't verify my guess that `std::array::iterator` is always a pointer (it seems it doesn't have to be). – leemes Oct 11 '15 at 18:31
  • I have followed the same approach [here](https://github.com/iavr/xio/blob/master/c%2B%2B/config.hpp), where I needed such a trait for low-level input/output. As you see, you can include `std::basic_string` and exclude `std::vector`. – iavr Oct 11 '15 at 21:54