Я обнаружил, что мне нужно много раз идентифицировать типы, выполняющие эту функцию. Я не знаю, является ли изобретение такой особой «концепции» элегантной (представьте, что это концепция, которая включает в себя память, которая не очень абстрактна), но я согласен, что что-то подобное будет полезно.
Между тем, чтобы быть практичным и перевести эту концепцию/требование в чистое требование синтаксиса, давайте пройдем назад. Если мы ограничимся стандартом, то каковы классы, которые гарантируют (или почти гарантируют) соприкосновение? в порядке значимости:
std::vector<T>
T[N] // !!
std::array<T, N>
std::string
std::initializer_list<T>
std::valarray<T>
Из всех этих, std::vector
, std::array
, std::string
имеют функцию члена под названием .data()
. Итак, если этого достаточно для вас, можно положиться на присутствие члена .data() -> T*
, чтобы указать непрерывную память.
У вас есть два варианта:
1) сделать усилия использовать функцию-член .data()
поднять синтаксическую ошибку, если тип не является непрерывным. (Не сложно, если вы замените, например, t[0]
на *t.data()
)
2) Используйте какой-то SFINAE на .data()
.
template<class ContiguousSequence, typename = decltype(std::declval<ContigiousSequence>().data())>
void fun(ContiguousSequence&& s){...} // this function will only work with contiguous data
Кроме того, C++ 17 имеет std::data
обобщающую его ко всем типам с .data()
и дополнительно перегружает для T[N]
и std::initializer_list<T>
. Итак, вы можете заменить ....data()
на std::data(...)
выше.
Вывод, я думаю, что это хорошо конвенции является то, что если тип имеет data
функцию (или .data()
в C++ 11), которая возвращает указатель на тип значения, то элементы являются смежными.
(Хорошо, что о std::valarray<T>
? Это не работает, если вы не перегружать std::data(std::valarray<T>&)
. Но кто использует std::valarray
так или иначе? Это довольно заброшенный угол C++, я думаю)
Наконец, обратите внимание на пример, который, очевидно, std::map
и менее очевидно std::deque
не имеет функции .data()
(или std::data(...)
). boost::multi_array<..., N>
имеет член .data()
и возвращает указатель на элемент массива, неясно, является ли это непрерывной последовательностью в том смысле, в котором вы хотите (поскольку порядок не очевиден), но в некотором смысле это также непрерывное распределение памяти.
РЕДАКТИРОВАТЬ: Есть два предложения в настоящее время решения этой проблемы (но на уровне итераторов) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdfhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html
'std :: array';) – Zeta
Насколько я знаю, такой концепции нет. 'std :: vector',' std :: string' и 'std :: array' просто имеют инвариант, что' c.data() + i == & c [i] 'для' i' в '[0, c .size()) '. – Xeo
@Xeo: Правильно. Нет понятия, только требование, чтобы элементы (или 'char_type') были «сохранены смежно» *. – Zeta