Есть ли способ проверить, является ли произвольный тип переменной итеративным?
Итак, чтобы проверить, имеет ли он проиндексированные элементы, или я могу на самом деле зациклить его детей? (Например, использовать foreach?)
Возможно ли создать универсальный шаблон для этого?
Я нашел методы для других языков программирования при поиске. Еще предстоит выяснить, как это сделать в C ++.
Это зависит от того, что вы подразумеваете под «итеративным». Это свободная концепция в C ++, поскольку вы можете реализовать итераторы различными способами.
Если по foreach
вы имеете в виду циклы, основанные на диапазонах C ++ 11, тип требует begin()
а также end()
методы, которые будут определены и возвращать итераторы, которые отвечают на operator!=
,
operator++
а также operator*
,
Если вы имеете в виду помощника Boost BOOST_FOREACH, то смотрите BOOST_FOREACH Расширяемость.
Если в вашем проекте есть общий интерфейс, от которого наследуются все итерируемые контейнеры, то вы можете использовать C ++ 11 станд :: is_base_of:
struct A : IterableInterface {}
struct B {}
template <typename T>
constexpr bool is_iterable() {
return std::is_base_of<IterableInterface, T>::value;
}
is_iterable<A>(); // true
is_iterable<B>(); // false
Вы можете создать черту для этого:
namespace detail
{
// To allow ADL with custom begin/end
using std::begin;
using std::end;
template <typename T>
auto is_iterable_impl(int)
-> decltype (
begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
void(), // Handle evil operator ,
++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
void(*begin(std::declval<T&>())), // operator*
std::true_type{});
template <typename T>
std::false_type is_iterable_impl(...);
}
template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));
да используя это класс черт совместимый C ++ 03
template<typename C>
struct is_iterable
{
typedef long false_type;
typedef char true_type;
template<class T> static false_type check(...);
template<class T> static true_type check(int,
typename T::const_iterator = C().end());
enum { value = sizeof(check<C>(0)) == sizeof(true_type) };
};
check<C>(0)
звонки check(int,const_iterator)
если C::end()
существует и возвращает const_iterator
совместимый типcheck<C>(0)
звонки check(...)
(увидеть эллипсис)sizeof(check<C>(0))
зависит от типа возвращаемого значения этих функцийvalue
в true
или же false
#include <iostream>
#include <set>
int main()
{
std::cout <<"set="<< is_iterable< std::set<int> >::value <<'\n';
std::cout <<"int="<< is_iterable< int >::value <<'\n';
}
set=1
int=0
Замечания: C ++ 11 (и C ++ 14) предоставляет множество черты классов но не про итеративность …
Смотрите также похожие ответы от Джрок а также Jarod42.
Этот ответ находится в общественном достоянии — CC0 1.0 Универсальный
У cpprefence есть пример ответа на ваш вопрос. Он использует SFINAE, Вот немного измененная версия этого примера (в случае, если содержание этой ссылки изменяется со временем):
template <typename T, typename = void>
struct is_iterable : std::false_type {};
// this gets used only when we can call std::begin() and std::end() on that type
template <typename T>
struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T>())),
decltype(std::end(std::declval<T>()))
>
> : std::true_type {};
// Here is a helper:
template <typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;
Вот как это можно использовать
std::cout << std::boolalpha;
std::cout << is_iterable_v<std::vector<double>> << '\n';
std::cout << is_iterable_v<std::map<int, double>> << '\n';
std::cout << is_iterable_v<double> << '\n';
struct A;
std::cout << is_iterable_v<A> << '\n';
Выход:
true
true
false
false
Сказав это, все это проверяет, декларация begin() const
а также end() const
соответственно, даже следующее проверяется как повторяемое:
struct Container
{
void begin() const;
void end() const;
};
std::cout << is_iterable_v<Container> << '\n'; // prints true
Вы можете увидеть эти кусочки вместе Вот
Невозможно проверить, является ли произвольный тип переменной итеративным. Хотя есть некоторые распространенные типы, для которых это можно сделать, но проверка будет во время компиляции, а не во время выполнения.
Контейнеры в стиле STL в c ++ предоставляют доступ к элементам begin и end. Наличие этих членов можно использовать для определения вероятности повторяемости типа.
Примитивный тип массива в c ++ вносит некоторую загадку. Адрес первого допустимого индекса и адрес, следующий за последним допустимым индексом, могут использоваться в качестве допустимых начальных и конечных итераторов. Однако массивы c ++ не показывают их длину; Вы должны хранить это в отдельной переменной. Таким образом, чтобы определить «конечный итератор» массива, вам нужно две части информации: адрес первого индекса и длина массива. (На самом деле, вам также необходим третий фрагмент информации: ширина байта каждого индекса, но это, как правило, выводится из самого массива).