I found my self having to identify types fulfilling this feature many times. I don't know if inventing such a special "concept" is elegant (imagine that it is a concept that involves memory, which is not very abstract) but I agree something like this will be useful.
Meanwhile to be practical and translate this concept/requirement into a pure syntax requirement, let's walk backwards. If we restrict ourselves to the standard, what are the classes that guarantee (or almost guarantee) contiguity? in order of relevance:
std::vector<T>
T[N] // !!
std::array<T, N>
std::string
std::initializer_list<T>
std::valarray<T>
Of all these, std::vector
, std::array
, std::string
have a member function called .data()
. So, if this is enough for you, could rely on the presence of member .data() -> T*
to indicate contiguous memory.
You have two options:
1) Make the effort to use the member function .data()
to raise a syntax error if the type is not contiguous. (Not hard if you replace for example t[0]
by *t.data()
)
2) Use some kind of SFINAE on .data()
.
template<class ContiguousSequence, typename = decltype(std::declval<ContigiousSequence>().data())>
void fun(ContiguousSequence&& s){...} // this function will only work with contiguous data
Moreover, C++17 has std::data
which generalizes it to all types with .data()
and additionally overloads for T[N]
and std::initializer_list<T>
.
So, you can replace ....data()
by std::data(...)
above.
The conclusion, I think it is a good convention is that
if a type has a data
function (or .data()
in C++11) that returns a pointer to the value type then the elements
are contiguous.
(Ok, what about std::valarray<T>
? It doesn't work, unless you overload std::data(std::valarray<T>&)
. But who uses std::valarray
anyway? it is a pretty abandoned corner of C++, I think)
Finally, note for example that obviously std::map
and less obviously std::deque
don't have a .data()
(or std::data(...)
) function. boost::multi_array<..., N>
has a .data()
member and returns a pointer to the array element, it is not clear if this is contiguous sequence in the sense you want (because the order is not obvious) but in some sense it is also a contiguous allocation of memory.
EDIT:
There are two proposals currently addressing this issue (but at the level of the iterators) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html