Reputation: 545
Suppose I write template function that processes a range of elements.
template <typename Iter>
void func(Iter first, Iter last);
In this function I want to call some low-level c-function that expects to get contiguous buffer and it's size. Generic way to do this stuff is to copy my range to contiguous container and then call c-function.
template <typename Iter>
void func(Iter first, Iter last)
{
typedef typename iterator_traits<Iter>::value_type value_type;
vector<value_type> buf(first, last);
c_func((void*) buf.data(), buf.size() * sizeof(value_type));
}
But if iterators are already point to some contiguous memory space extra copying will be performed.
So the question is, is there a way to determine are iterators point to contiguous memory space and if it is how can I specialize my function for this case.
Upvotes: 3
Views: 232
Reputation: 153840
At the moment there is no direct way to determine if an iterator is used for contiguous memory. There is a proposal to add an iterator refinement (see e.g. n3884) but without something like that and a way to detect the property being added for the different iterators you'll have a hard time determining this trait.
The key problem requiring implementer support is that the name if iterator types is not specified. As a result, you can't create a traits applicable to all known to be contiguous iterator types. Since the iterator types for std::vector<T>
and std::array<T>
can be identical and T*
I don't think you can even create a portable specialization.
What you could do, however, is to test in a trait whether an iterator type matches one of the known iterator types for its value type. For example:
template <typename T, typename It>
struct test_iterator
: std::integral_constant<bool,
std::is_same<T*, It>::value
|| std::is_same<typename std::vector<T>::iterator, It>::value
|| std::is_same<std::string::iterator, It>::value
|| std::is_same<std::wstring::iterator, It>::value
> {
};
template <typename It>
struct is_contiguous
: std::integral_constant<bool,
test_iterator<typename std::iterator_traits<It>::value_type,
It>::value> {
};
[I haven't tried to compile the code, i.e., it is probably littered with small typos; the general approach should work, though]
To add, e.g., std::array<T, N>
you'd need some way to figure out the dimension in a static way. I guess, that won't be viable. It may also be necessary to test the various const_iterator
s.
Upvotes: 3