Проверьте, находится ли элемент в std:: initializer_list
Я хочу иметь возможность писать на С++ нечто похожее на следующий код Python:
if x in [1, 2, 3, 5] ...
чтобы проверить, содержится ли элемент в наборе жестко заданных значений, определенных на месте. Вот так:
if (in(x, {1, 2, 3, 5})) ...
Вот возможная реализация функции in
:
template<class T>
bool in(const T& x, std::initializer_list<T> c)
{
return std::find(c.begin(), c.end(), x) != c.end();
}
Мой вопрос: действительно ли мне нужно написать эту функцию самостоятельно? Существуют ли какие-либо реализации по умолчанию там? Может быть, в boost? Я проверил boost::contains
, но работает только со строками.
Ответы
Ответ 1
Если у вас есть доступ к c++20 вы можете использовать set
contains
, который возвращает bool
, позволяющее сделать:
if(set{ 4, 8, 15, 16, 23, 42 }.contains(x))
Live Example
Если у вас нет c++20, вы все равно можете использовать set
count
который возвращает только 1 или 0, что позволяет вам сделать что-то вроде:
if(set<int>{ 4, 8, 15, 16, 23, 42 }.count(x) > 0U)
Имейте в виду, что магические числа могут сбить с толку вашу аудиторию (и вызвать 5 сезонов Lost.)
Я бы рекомендовал объявить ваши номера как const initializer_list<int>
и дать им значимое имя:
const auto finalCandidates{ 4, 8, 15, 16, 23, 42 };
if(cend(finalCandidates) != find(cbegin(finalCandidates), cend(finalCandidates), x))
Ответ 2
boost::algorithm::contains
работает не только на строках, но и работает на любом диапазоне, то есть в последовательности, которая может дать начало и конец итератора. Чтобы найти одно значение, используйте его следующим образом:
auto l = {1,2,3,4};
auto l1 = {2}; // thing you want to find
if(boost::algorithm::contains(l, l1)) { ... }
Вы можете выполнять поиск, используя только стандартную библиотеку, но это довольно немного подробней. Пара вариантов:
-
используя lambda
if(std::any_of(l.begin(), l.end(),
[](int i){ return i == 2; })) { ... }
-
используя std::bind
using std::placeholders::_1;
if(std::any_of(l.begin(), l.end(),
std::bind(std::equal_to<>(), 2, _1)) { ... }
Живая демонстрация
Обратите внимание, что std::equal_to<>()
- это опция только для С++ 14. Для компилятора С++ 11 используйте std::equal_to<int>()
.
Ответ 3
В действительности STL не имеет простой функции std::contains()
. Недавно в этой теме было обсуждение reddit.
К сожалению, из этого вышло, что считать std::contains()
вредным, поскольку он побуждает людей писать медленные алгоритмы. Подумайте, например, о
if (!std::contains(my_set.begin(), my_set.end(), entry)) {
my_set.insert(insert);
}
Этот пример кода в основном ищет правильное положение дважды: один раз внутри содержит и один раз, чтобы найти место вставки.
По-моему, было бы очень полезно иметь std::contains()
, но пока никто не был убежден написать предложение.
Так что либо используйте boost (как было предложено другим в этом потоке), либо напишите свою собственную функцию, которую вы по существу уже сделали: -)