Created
August 9, 2014 23:02
-
-
Save panzi/869728c9879dcd4fffa8 to your computer and use it in GitHub Desktop.
Match arrays and classes that implement methods needed to be iterable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// $ g++ -Wall -Wextra -Werror -pedantic -std=c++1y is_iterable.cpp -O3 -o is_iterable | |
#include <type_traits> | |
#include <iterator> | |
#include <iostream> | |
#include <iomanip> | |
#include <vector> | |
#include <list> | |
#include <array> | |
#include <set> | |
#include <map> | |
#include <unordered_set> | |
#include <unordered_map> | |
#include <deque> | |
#include <forward_list> | |
template<typename T> | |
struct is_iterator { | |
private: | |
template<typename I> static constexpr auto test(void*) | |
-> decltype( | |
*std::declval<const I>(), | |
std::declval<const I>() == std::declval<const I>(), | |
std::declval<const I>() != std::declval<const I>(), | |
++ (*std::declval<I*>()), | |
(*std::declval<I*>()) ++, | |
std::true_type()) { return std::true_type(); } | |
template<typename I> static constexpr std::false_type test(...) { return std::false_type(); } | |
public: | |
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value; | |
}; | |
namespace impl { | |
// implementation details | |
template<typename T> | |
struct has_iterable_methods { | |
private: | |
template<typename C> static constexpr auto test(void*) | |
-> decltype( | |
std::declval<C>().begin(), | |
std::declval<C>().end(), | |
std::true_type()) { return std::true_type(); } | |
template<typename C> static constexpr std::false_type test(...) { return std::false_type(); } | |
public: | |
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value; | |
}; | |
template<typename T, bool HasIterableMethods> | |
struct returns_iterators : public std::false_type {}; | |
template<typename T> | |
struct returns_iterators<T, true> { | |
typedef decltype(std::declval<T>().begin()) begin_type; | |
typedef decltype(std::declval<T>().end()) end_type; | |
static constexpr const bool value = | |
std::is_same<begin_type, end_type>::value && | |
is_iterator<begin_type>::value; | |
}; | |
} | |
template<typename T> | |
struct is_iterable : public std::integral_constant< | |
bool, | |
impl::returns_iterators< | |
typename std::remove_const<T>::type, | |
impl::has_iterable_methods<typename std::remove_const<T>::type>::value>::value> {}; | |
template<typename T, std::size_t N> | |
struct is_iterable<T[N]> : public std::true_type {}; | |
template<typename T> | |
struct is_iterable<T*> : public std::false_type {}; | |
// test types | |
struct MyIterable { | |
int* begin() { return 0; } | |
int* end() { return 0; } | |
}; | |
struct MyIterableConst { | |
const int* begin() const { return 0; } | |
const int* end() const { return 0; } | |
}; | |
struct MyIterableBoth { | |
int* begin() { return 0; } | |
int* end() { return 0; } | |
const int* begin() const { return 0; } | |
const int* end() const { return 0; } | |
}; | |
struct NotIterable {}; | |
struct OnlyBegin { | |
const int* begin() const { return 0; } | |
}; | |
struct OnlyEnd { | |
const int* end() const { return 0; } | |
}; | |
struct WrongReturnTypes { | |
void begin() const {} | |
void end() const {} | |
}; | |
struct TypeMissmatch { | |
int* begin() const { return 0; } | |
float* end() const { return 0; } | |
}; | |
int main () { | |
int array[] = {1, 2, 3}; | |
const int carray[] = {1, 2, 3}; | |
typedef int A[3]; | |
typedef std::vector<int> B; | |
std::cout << std::boolalpha | |
<< "typedef int A[3];\n" | |
<< "typedef std::vector<int> B;\n" | |
<< "int array[] = {1, 2, 3};\n" | |
<< "const int carray[] = {1, 2, 3};\n" | |
<< "\n" | |
<< "Iterable:\n" | |
<< "=========\n" | |
<< "is_iterable<std::vector<int>>::value = " << is_iterable<std::vector<int>>::value << "\n" | |
<< "is_iterable<std::list<int>>::value = " << is_iterable<std::list<int>>::value << "\n" | |
<< "is_iterable<std::array<int,3>>::value = " << is_iterable<std::array<int,3>>::value << "\n" | |
<< "is_iterable<std::set<int>>::value = " << is_iterable<std::set<int>>::value << "\n" | |
<< "is_iterable<std::map<int,int>>::value = " << is_iterable<std::map<int,int>>::value << "\n" | |
<< "is_iterable<std::unordered_set<int>>::value = " << is_iterable<std::unordered_set<int>>::value << "\n" | |
<< "is_iterable<std::unordered_map<int,int>>::value = " << is_iterable<std::unordered_map<int,int>>::value << "\n" | |
<< "is_iterable<std::deque<int>>::value = " << is_iterable<std::deque<int>>::value << "\n" | |
<< "is_iterable<std::forward_list<int>>::value = " << is_iterable<std::forward_list<int>>::value << "\n" | |
<< "is_iterable<decltype(array)>::value = " << is_iterable<decltype(array)>::value << "\n" | |
<< "is_iterable<decltype(carray)>::value = " << is_iterable<decltype(carray)>::value << "\n" | |
<< "is_iterable<std::string>::value = " << is_iterable<std::string>::value << "\n" | |
<< "is_iterable<MyIterable>::value = " << is_iterable<MyIterable>::value << "\n" | |
<< "is_iterable<const MyIterable>::value = " << is_iterable<const MyIterable>::value << "\n" | |
<< "is_iterable<MyIterableConst>::value = " << is_iterable<MyIterableConst>::value << "\n" | |
<< "is_iterable<const MyIterableConst>::value = " << is_iterable<const MyIterableConst>::value << "\n" | |
<< "is_iterable<MyIterableBoth>::value = " << is_iterable<MyIterableBoth>::value << "\n" | |
<< "is_iterable<const MyIterableBoth>::value = " << is_iterable<const MyIterableBoth>::value << "\n" | |
<< "is_iterable<int[3]>::value = " << is_iterable<int[3]>::value << "\n" | |
<< "is_iterable<const int[3]>::value = " << is_iterable<const int[3]>::value << "\n" | |
<< "is_iterable<int[]>::value = " << is_iterable<int[]>::value << "\n" | |
<< "is_iterable<int*>::value = " << is_iterable<int*>::value << "\n" | |
<< "is_iterable<const int*>::value = " << is_iterable<const int*>::value << "\n" | |
<< "is_iterable<int>::value = " << is_iterable<int>::value << "\n" | |
<< "is_iterable<const int>::value = " << is_iterable<const int>::value << "\n" | |
<< "is_iterable<NotIterable>::value = " << is_iterable<NotIterable>::value << "\n" | |
<< "is_iterable<OnlyBegin>::value = " << is_iterable<OnlyBegin>::value << "\n" | |
<< "is_iterable<OnlyEnd>::value = " << is_iterable<OnlyEnd>::value << "\n" | |
<< "is_iterable<WrongReturnTypes>::value = " << is_iterable<WrongReturnTypes>::value << "\n" | |
<< "is_iterable<TypeMissmatch>::value = " << is_iterable<TypeMissmatch>::value << "\n" | |
<< "\n" | |
<< "Iterator:\n" | |
<< "=========\n" | |
<< "is_iterator<std::vector<int>::const_iterator>::value = " << is_iterator<std::vector<int>::const_iterator>::value << "\n" | |
<< "is_iterator<std::vector<int>::iterator>::value = " << is_iterator<std::vector<int>::iterator>::value << "\n" | |
<< "is_iterator<decltype(std::begin(std::declval<const A>()))>::value = " << is_iterator<decltype(std::begin(std::declval<const A>()))>::value << "\n" | |
<< "is_iterator<decltype(std::begin(std::declval<const B>()))>::value = " << is_iterator<decltype(std::begin(std::declval<const B>()))>::value << "\n" | |
<< "is_iterator<int*>::value = " << is_iterator<int*>::value << "\n" | |
<< "is_iterator<const char*>::value = " << is_iterator<const char*>::value << "\n" | |
<< "is_iterator<int>::value = " << is_iterator<int>::value << "\n" | |
<< "is_iterator<void>::value = " << is_iterator<void>::value << "\n" | |
<< "is_iterator<void*>::value = " << is_iterator<void*>::value << "\n" | |
<< "is_iterator<int[3]>::value = " << is_iterator<int[3]>::value << "\n" | |
<< "is_iterator<int[]>::value = " << is_iterator<int[]>::value << "\n"; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef int A[3]; | |
typedef std::vector<int> B; | |
int array[] = {1, 2, 3}; | |
const int carray[] = {1, 2, 3}; | |
Iterable: | |
========= | |
is_iterable<std::vector<int>>::value = true | |
is_iterable<std::list<int>>::value = true | |
is_iterable<std::array<int,3>>::value = true | |
is_iterable<std::set<int>>::value = true | |
is_iterable<std::map<int,int>>::value = true | |
is_iterable<std::unordered_set<int>>::value = true | |
is_iterable<std::unordered_map<int,int>>::value = true | |
is_iterable<std::deque<int>>::value = true | |
is_iterable<std::forward_list<int>>::value = true | |
is_iterable<decltype(array)>::value = true | |
is_iterable<decltype(carray)>::value = true | |
is_iterable<std::string>::value = true | |
is_iterable<MyIterable>::value = true | |
is_iterable<const MyIterable>::value = true | |
is_iterable<MyIterableConst>::value = true | |
is_iterable<const MyIterableConst>::value = true | |
is_iterable<MyIterableBoth>::value = true | |
is_iterable<const MyIterableBoth>::value = true | |
is_iterable<int[3]>::value = true | |
is_iterable<const int[3]>::value = true | |
is_iterable<int[]>::value = false | |
is_iterable<int*>::value = false | |
is_iterable<const int*>::value = false | |
is_iterable<int>::value = false | |
is_iterable<const int>::value = false | |
is_iterable<NotIterable>::value = false | |
is_iterable<OnlyBegin>::value = false | |
is_iterable<OnlyEnd>::value = false | |
is_iterable<WrongReturnTypes>::value = false | |
is_iterable<TypeMissmatch>::value = false | |
Iterator: | |
========= | |
is_iterator<std::vector<int>::const_iterator>::value = true | |
is_iterator<std::vector<int>::iterator>::value = true | |
is_iterator<decltype(std::begin(std::declval<const A>()))>::value = true | |
is_iterator<decltype(std::begin(std::declval<const B>()))>::value = true | |
is_iterator<int*>::value = true | |
is_iterator<const char*>::value = true | |
is_iterator<int>::value = false | |
is_iterator<void>::value = false | |
is_iterator<void*>::value = false | |
is_iterator<int[3]>::value = false | |
is_iterator<int[]>::value = false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment