Если вы используете итераторы и диапазоны вместо прямой работы с контейнером, вы можете создать алгоритм, который эффективно работает с любым контейнером (включая связанные списки), а также с потоками:
#include <list>
#include <array>
#include <vector>
#include <iterator>
template <typename T>
bool checkUniformity(T begin, T end) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!((*last).isUniform(*begin)))
return false;
last = begin;
}
return true;
}
template <typename T, typename F>
bool checkUniformity(T begin, T end, F pred) {
// Check for empty range
if (begin == end) return true;
// Remember last element
T last = begin;
while (++begin != end) {
if (!pred(*last, *begin))
return false;
last = begin;
}
return true;
}
struct Foo
{
bool isUniform(const Foo& other) const;
};
int main () {
// I want to call it in both ways:
std::vector<Foo> vec;
std::array<Foo, 3> arr;
std::list<Foo> list;
Foo carr [3];
bool b1 = checkUniformity(std::cbegin(vec), std::cend(vec));
bool b2 = checkUniformity(std::cbegin(arr), std::cend(arr));
bool b3 = checkUniformity(std::cbegin(list), std::cend(list));
bool b4 = checkUniformity(std::cbegin(carr), std::cend(carr));
bool b1_2 = checkUniformity(std::cbegin(vec), std::cend(vec), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b2_2 = checkUniformity(std::cbegin(arr), std::cend(arr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b3_2 = checkUniformity(std::cbegin(list), std::cend(list), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
bool b4_2 = checkUniformity(std::cbegin(carr), std::cend(carr), [] (const Foo& a, const Foo& b) { return a.isUniform(b); });
}
Вы также можетереализовать второй вариант, как показано, где вы можете указать условие как предикат (например, лямбда, как показано), если у вас есть разные варианты isUniform
. Потребность передать два параметра для диапазона вместо просто контейнера немного более громоздка, но намного более гибка;он также позволяет запускать алгоритм в поддиапазоне контейнера.
Это тот же подход, который используется алгоритмами стандартной библиотеки, такими как std::find
.