I'd like to specialize std::iterator_traits<> for iterators of a container class template that does not have the usual nested typedefs (like value_type, difference_type, etc.) and whose source I shouldn't modify. Basically I'd like to do something like this:
template <typename T> struct iterator_traits<typename Container<T>::iterator>
{
typedef T value_type;
// etc.
};
except that this doesn't work, as the compiler is unable to deduce T from Container<T>::iterator.
Is there any working way to achieve the same?
For example:
template <typename T>
class SomeContainerFromAThirdPartyLib
{
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
typedef T ValueType; // not value_type!
// no difference_type
...
};
iterator begin() { ... }
iterator end() { ... }
...
};
Now suppose I call std::count() using an instance of this class. As far as I know, in most STL implementations, count() returns iterator_traits<Iterator>::difference_type. The primary template of iterator_traits<I> simply does typedef typename I::difference_type difference_type. Same with the other nested types.
Now in our example this obviously won't work, as there's no Container::iterator::difference_type. I thought I could work around this without modifying the iterator class, by specializing iterator_traits for iterators of any Container<T>.
In the end, I just want to be able to use std algorithms like count, find, sort, etc., preferably without modifying any existing code. I thought that the whole point of iterator_traits is exactly that: being able to specify types (like value_type, diff_type etc.) for iterator types that do not support them built-in. Unfortunately I can't figure out how to specialize the traits class for all instances of Container<T>.
Yes. The compiler cannot deduce T from Container<T>::iterator because it is non-deducible context, which in other words means, given Container<T>::iterator, the value of T cannot uniquely and reliably be deduced (see this for detail explanation).
The only solution to this problem is that you've to fully specialize iterator_traits for each possible value of iterator which you intend to use in your program. There is no generic solution, as you're not allowed to edit the Container<T> class template.
Nawaz's answer is likely the right solution for most cases. However, if you're trying to do this for many instantiated SomeContainerFromAThirdPartyLib<T> classes and only a few functions (or an unknown number of instantiations but a fixed number of functions, as might happen if you're writing your own library), there's another way.
Assume we're given the following (unchangeable) code:
namespace ThirdPartyLib
{
template <typename T>
class SomeContainerFromAThirdPartyLib
{
public:
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
public:
typedef T ValueType; // not value_type!
// no difference_type
// obviously this is not how these would actually be implemented
int operator != (const iterator& rhs) { return 0; }
iterator& operator ++ () { return *this; }
T operator * () { return T(); }
};
// obviously this is not how these would actually be implemented
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
};
}
We define an adapter class template containing the necessary typedefs for iterator_traits and specialize it to avoid problems with pointers:
namespace MyLib
{
template <typename T>
class iterator_adapter : public T
{
public:
// replace the following with the appropriate types for the third party iterator
typedef typename T::ValueType value_type;
typedef std::ptrdiff_t difference_type;
typedef typename T::ValueType* pointer;
typedef typename T::ValueType& reference;
typedef std::input_iterator_tag iterator_category;
explicit iterator_adapter(T t) : T(t) {}
};
template <typename T>
class iterator_adapter<T*>
{
};
}
Then, for each function we want to be able to call with a SomeContainerFromAThirdPartyLib::iterator, we define an overload and use SFINAE:
template <typename iter>
typename MyLib::iterator_adapter<iter>::difference_type
count(iter begin, iter end, const typename iter::ValueType& val)
{
cout << "[in adapter version of count]";
return std::count(MyLib::iterator_adapter<iter>(begin), MyLib::iterator_adapter<iter>(end), val);
}
We can then use it as follows:
int main()
{
char a[] = "Hello, world";
cout << "a=" << a << endl;
cout << "count(a, a + sizeof(a), 'l')=" << count(a, a + sizeof(a), 'l') << endl;
ThirdPartyLib::SomeContainerFromAThirdPartyLib<int> container;
cout << "count(container.begin(), container.end(), 0)=";
cout << count(container.begin(), container.end(), 0) << std;
return 0;
}
You can find a runnable example with the required includes and usings at http://ideone.com/gJyGxU. The output:
a=Hello, world
count(a, a + sizeof(a), 'l')=3
count(container.begin(), container.end(), 0)=[in adapter version of count]0
Unfortunately, there are caveats:
As I said, an overload needs to be defined for each function you plan to support (find, sort, et cetera). This obviously won't work for functions in algorithm that haven't been defined yet.
If not optimized out, there may be small run-time performance penalties.
There are potential scoping issues.
In regards to that last one, the question is in which namespace to put the overload (and how to call the std version). Ideally, it would be in ThirdPartyLib so that it could be found by argument-dependant lookup, but I've assumed we can't change that. The next best option is in MyLib, but then the call has to be qualified or preceded by a using. In either case the end-user should either use using std::count; or be careful about which calls to qualify with std::, since if std::count is mistakenly used with SomeContainerFromAThirdPartyLib::iterator, it will obviously fail (the whole reason for this exercise).
An alternative that I do not suggest but present here for completeness would be to put it directly in the std namespace. This would cause undefined behavior; while it might work for you, there's nothing in the standard that guarantees it. If we were specializing count instead of overloading it, this would be legal.
In the specialization in question, T is in a nondeducible context but there is neither a third party library container code change nor any specialization in the std namespace required.
If the third party library does not provide any free begin and end functions in the respective namespace one can write own functions (into that namespace if desired to enable ADL) and wrap the iterator into an own wrapper class which in turn provides the necessary typedefs and operators.
First one needs the Iterator wrapper.
#include <cstddef>
namespace ThirdPartyStdAdaptor
{
template<class Iterator>
struct iterator_wrapper
{
Iterator m_it;
iterator_wrapper(Iterator it = Iterator())
: m_it(it) { }
// Typedefs, Operators etc.
// i.e.
using value_type = typename Iterator::ValueType;
using difference_type = std::ptrdiff_t;
difference_type operator- (iterator_wrapper const &rhs) const
{
return m_it - rhs.m_it;
}
};
}
Note: It would also be possible to make iterator_wrapper inherit from Iterator, or to make it more generic and have another helper to enable the wrapping of other iterators as well.
Now begin() and end():
namespace ThirdPartyLib
{
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator> begin(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper<typename
SomeContainer<T>::iterator>(c.begin());
}
template<class T>
ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > end(SomeContainer<T> &c)
{
return ThirdPartyStdAdaptor::iterator_wrapper < typename
SomeContainer<T>::iterator > (c.end());
}
}
(It is also possible to have them in a different namespace than SomeContainer but loose ADL. IF there are begin and end functions present in the namespace for that container I'd tend to rename the adaptors to be something like wbegin and wend.)
The standard algorithms can be called using those functions now:
ThirdPartyLib::SomeContainer<SomeType> test;
std::ptrdiff_t d = std::distance(begin(test), end(test));
If begin() and end() are included into the library namespace, the container can even be used in more generic contexts.
template<class T>
std::ptrdiff_t generic_range_size(T const &x)
{
using std::begin;
using std::end;
return std::distance(begin(x), end(x));
}
Such code can be used with std::vector as well as ThirdPartyLib::SomeContainer, as long as ADL finds begin() and end() returning the wrapper iterator.
You can very well use the Container as template parameter to your iterator_traits. What matters to the rest of STL are the typedefs inside your traits class, such as value_type. Those should be set correctly:
template <class Container> struct iterator_traits
{
public:
typedef typename Container::value_type value_type;
// etc.
};
You would then use value_type where you would previously use T.
As for using the traits class, you of course parametrize it with the type of your external container:
iterator_traits<TheContainer> traits;
Naturally, this assumes TheContainer is conforms to the common STL containers' contract and has value_type defined correctly.
Related
Let's say I'm implementing a collection, say something like std::vector. I need to implement iterator and const_iterator, but once I've made iterator can const_iterator not just be implemented as iterator<const T> (where T is the type contained in the collection)?
There must be some reason why this doesn't work because there are a million questions about how to re-use code while implementing iterator and const_iterator but none of them say "just use const T as the type".
std::iterator_traits<Iter>::value_type should be T for const_iterator<T>, but const T1 for iterator<const T>. If you use iterator<const T> as const_iterator<T>, you would have to violate one of these assumptions.
It should possible to use a common template for both iterators as long as constness of the value type is a separate template argument from constness of the iterator. Something like:
template<class T>
struct container
{
template<class ItPtr>
struct iterator_common
{
using value_type = T;
using pointer = ItPtr;
using reference = std::remove_pointer_t<ItPtr>&;
// ...
};
using iterator = iterator_common<T*>;
using const_iterator = iterator_common<const T*>;
// ...
};
1 Until C++20, in which it should be std::remove_cv_t<const T> which is T. As such, this won't be a problem to your suggestion in the future standard version.
I'm writing different sort functions, which take two iterators and sort sequence. I would like to implement them for any kind of vector and make them typesafe, like this:
template <typename T>
void itsort(std::vector<T>::iterator begin, std::vector<T>::iterator end)
{
// code
}
But due to errors I'm only able to implement something type-unsafe:
template <typename T>
void itsort(T begin, T end)
{
// code
}
How to implement type-safe template function, which takes two vector iterators?
PS: Currently there is no need in comparator, all sorts work with different types of numbers.
Determining if something is an iterator of a vector is hard, and mostly pointless.
The type of vector iterators are extremely free under the standard. They can even be naked pointers in some implementations.
What more, the type of the vector that produces the iterator might not be deducible from the iterator. As an example, a std::vector<int, some_allocator>::iterator might be a different, or the same type, as a std::vector<int>::iterator. They could both be int*, or they could be some class wrapped around a pointer. They could be the same type, or different types. (The technique of using the same type for different container types is called SCARY iterators if you want to find discussion about it).
In general, you cannot determine if a given iterator is a vector iterator.
You can write code that will fail if the given iterator is not a random-access iterator, and deduce the type T. First, a bit of boilerplate to make the access to iterator_traits a bit less verbose:
namespace iterators {
template<class It>
using iterator_category =
typename std::iterator_traits<It>::iterator_category;
template<class It>
using value_type =
typename std::iterator_traits<It>::value_type;
}
now we do this:
template<class It>
void itsort(It begin, It end)
{
using T = iterator::value_type<It>;
using category = iterator::iterator_category<It>;
static_assert(
std::is_base_of<std::random_access_iterator_tag, category>::value, "This function only supports random-access iterators"
);
}
this "fails late", in that the error does not occur at the time of overload resolution (SFINAE), but it does check your types for you.
You also have access to the underlying value type of your iterators.
Doing this in a SFINAE friendly way is difficult, because iterator_traits is not mandated to be SFINAE friendly, and iterator_traits is the mandated way to determine the traits of an iterator. As a concrete example, void* often matches the empty iterator_traits for pointers, but then it fails because it isn't an iterator.
seems you are looking for something like this:
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
template< typename T >
void itsort(T, T, std::bidirectional_iterator_tag)
{
std::cout << "itsort called for bidirectional iterator\n";
}
template <typename T>
void itsort(T, T, std::random_access_iterator_tag)
{
std::cout << "itsort called for random-access iterator\n";
}
template< typename T >
void alg(T first, T last)
{
itsort(first, last, typename std::iterator_traits<T>::iterator_category());
}
int main()
{
std::vector<int> v;
alg(v.begin(), v.end());
std::list<int> l;
alg(l.begin(), l.end());
}
Here's a container:
namespace container_namespace
{
template <class element_type, class element_allocator_type = std::allocator<element_type> >
class container
{
// stuff
class iterator
{
// stuff
};
};
}
Where in the above do I define advance(InputIt &, Distance N) in order to be allowed to use advance() in my main() via ADL (Argument-dependent lookup):
int main(int argc, char **argv)
{
using namespace std;
using namespace container_namespace;
container<int> c;
// Add elements to c here
container<int>::iterator it = c.begin();
advance(it, 20);
}
And have the custom advance() function selected instead of std::advance?
I have seen examples of the custom advance() function being defined inside the iterator class, and examples where it was defined inside the namespace with only the friendship being declared inside the iterator class. Which is correct to enable use of ADL? Other examples on SO were not clear on this point.
I believe the safest way is to define it friend of container or iterator. The function defined in such way is put into namespace container_namespace so it can be found by ADL:
namespace container_namespace {
template <class element_type, class element_allocator_type = std::allocator<element_type> >
class container {
//...
template <typename Diff>
friend void advance(iterator&, Diff) {
//...
}
};
}
DEMO
Another option could be to define it directly in namespace container_namespace. This way you can have common implementation for all your containers and/or implement tag dispatch to handle different iterator categories, as it's done in std::advance implementation:
namespace container_namespace {
template <typename Iter, typename Diff>
void advance(Iter&, Diff) {
std::cout << "ADL-ed advance\n";
}
}
The problem with this approach is that it can cause ambiguity when std::advance is in scope (thanks, #TC):
DEMO
Note also, that you can't define advance as follows:
namespace container_namespace {
template <typename element_type, typename element_allocator_type, typename Diff>
void advance(typename container<element_type, element_allocator_type>::iterator&, Diff) {
std::cout << "ADL-ed advance\n";
}
}
because the type of its first argument would fail (see Non-deduced contexts).
Unqualified name lookup will consider both whatever found by ordinary lookup (in your case, the function template std::advance) and what is found by ADL (in your case, advance(iterator&, Distance N). They will be considered by overload resolution on equal grounds.
Your goal is to make sure that your custom advance is the better match, and the simplest way to do so is to make sure it is a non-template function: templates lose to non-templates if they are otherwise equally as good. If your iterator is a class template (or, as shown, a member of a class template), you could make your advance a non-template friend defined inside the class template definition.
Although both the posted answers are correct (and I have upvoted both) I thought I would cover this in a little more depth, for anyone who finds this in future.
'Friend' meanings
For starters, 'friend' has a different meaning on functions within a class. If it is simply a function declaration, then it declares the given function a friend of the class and allows access to it's private/protected members. If however it is a function implementation, it means the function is (a) a friend of the class, (b) not a member of the class and (c) not accessible from within any enclosing namespace. ie. it becomes a global function which is only accessible via argument-dependent lookup (ADL).
Take the following test code for example:
#include <iostream>
#include <iterator>
namespace nsp
{
template <class element_type, class element_allocator_type = std::allocator<element_type> >
class test_container
{
private:
element_type numbers[50];
friend class iterator;
public:
class iterator : public std::iterator<std::bidirectional_iterator_tag, element_type>
{
private:
element_type *i;
template <class distance_type>
friend void advance(iterator &it, distance_type n);
friend typename std::iterator_traits<iterator>::difference_type distance(const iterator &first, const iterator &last)
{
return last.i - first.i;
}
public:
iterator(element_type &_i)
{
i = &(_i);
}
element_type & operator *()
{
return *i;
}
element_type & operator = (const iterator source)
{
i = source.i;
return *this;
}
bool operator != (const iterator rh)
{
return i != rh.i;
}
iterator & operator ++()
{
++i;
return *this;
}
iterator & operator --()
{
--i;
return *this;
}
};
iterator begin()
{
return iterator(numbers[0]);
}
iterator end()
{
return iterator(numbers[50]);
}
template <class distance_type>
friend void advance(iterator &it, distance_type n)
{
it.i += 2 * n;
}
};
}
int main(int argc, char **argv)
{
nsp::test_container<int> stuff;
int counter = 0;
for (nsp::test_container<int>::iterator it = stuff.begin(); it != stuff.end(); ++it)
{
*it = counter++;
}
nsp::test_container<int>::iterator it = stuff.begin(), it2 = stuff.begin();
using namespace std;
cout << *it << endl;
++it;
cout << *it << endl;
advance(it, 2);
cout << *it << endl;
std::advance(it, 2);
cout << *it << endl;
int distance_between = distance(it2, it);
cout << distance_between << endl;
cin.get();
return 0;
}
If, from within main(), advance() is called, ADL will function and the custom advance for the class iterator will be called. However, if nsp::advance(), nsp::test_container<int>::advance() or stuff.advance() are tried, these will result in compile errors ("no matching function call").
Template issues
While it is true that non-template function overloads will be called in preference of template function overloads, this is irrelevant for ADL usage. Regardless of whether the function is template or non-template, the correct overload for the specific type will be called. In addition, advance() specifically requires a template parameter of the distance type (int, long int, long long int etc), it is not possible to skip this because we don't know what type the compiler is going to infer from, say "1000000", and we don't know what kind of types the programmer might throw at advance(). Luckily we don't need to worry about partial specialization, as std::advance() is in a different namespace to our custom advance, and can simply implement our own advance() with our hardcoded iterator type, as the example above shows.
This still works if our iterator itself is a template and takes parameters - we simply include the parameters in the advance template and hardcode the template'd iterator type that way. eg.:
template <class element_type, class distance_type>
friend void advance(iterator<element_type>, distance_type distance);
More template issues (a side note)
While this doesn't relate specifically to the implementation of advance() it relates to the implementation of class friend functions in general. You will notice in the example above I implemented the non-template function distance() directly inside the iterator class, while the advance() template'd function is declared as a friend outside the iterator class but within the test_container class. This is to illustrate a point.
You cannot have a non-template friend function implemented outside the class it is friends with, if the class is a template (or part of a template) as your compiler will throw an error. However the template'd function advance() can be declared outside the class with only the definition included in the friend class. The advance() function can also be implemented directed within the friend class, I just chose not to in order to illustrate this point.
Template friend function parameter shadowing
This is not relevant to the above example but can be a pitfall for programmers stepping into template friend functions. If you have a template class, and a friend function which operates upon that class, obviously you are going to need to specify the template parameters in the function definition as well as the class. For example:
template <class element_type, class element_allocator_type = std::allocator<element_type> >
class test_container
{
private:
element_type numbers[50];
public:
template <class element_type, class element_allocator_type>
friend void do_stuff(test_container<element_type, element_allocator_type> &container)
{
numbers[1] = 5; // or whatever
}
};
However the above will not work because the compiler considers your using the same names for 'element_type' and 'element_allocator_type' to be a redefinition of the template parameters first used in the definition of test_container, and will throw an error. Therefore you must use different names for these. ie. this works:
template <class element_type, class element_allocator_type = std::allocator<element_type> >
class test_container
{
private:
element_type numbers[50];
public:
template <class c_element_type, class c_element_allocator_type>
friend void do_stuff(test_container<c_element_type, c_element_allocator_type> &container)
{
numbers[1] = 5; // or whatever
}
};
That's all-
I hope anybody stumbling across this gets some use out of it - most of this information is spread out across stackoverflow in some way, shape or form, but bringing it together is important for the novice.
[UPDATE:] Even with all of the above, it still may not be enough to correctly resolve the ADL to the correct function, despite it being 'correct'. This is because clang, microsoft visual studio 2010-2013, possibly others, have difficulties resolving ADL in complex templates and may crash or throw errors regardless. In this case, you would be wise to simply resort to standard container functions which are friended by the iterator classes.
You need two things to take advantage of ADL:
have the function or function template live in the right namespace
have the function or function template be a good enough candidate
The first thing is straightforward, but the second one requires a little bit of care. Here is something you should definitively not do:
template<typename Element, typename Allocator>
struct vector {
struct iterator {};
};
// trouble ahead!
template<typename Element, typename Allocator>
void advance(typename vector<Element, Allocator>::iterator it, int n)
{
…
}
In this particular form, as it turns out the template parameters Element and Allocator to advance are non-deducible. In other words, advance is only callable if the caller passes in those parameters e.g. ns::advance<int, std::allocator<int>>(it, n). Since calls to advance do not normally look like that this is a pretty awful candidate and we can outright rule it out.
Inline friends
A short and sweet solution is to define a friend function inline inside iterator. What’s crucial about this technique is that this does not define a function template, but a function—very much how vector<E, A>::iterator is not a class template but is itself a class, one per vector<E, A> specialization.
template<typename Element, typename Allocator>
struct vector {
struct iterator {
friend void advance(iterator it, int n)
{ … }
};
};
Live On Coliru
advance is found by ADL since it’s the right namespace, and since it’s a non-template function it is preferred over std::advance. All is well in the land, isn’t it? Well, there is a limitation in that you cannot take the address of ns::advance, in fact you can’t name it at all.
You can usually put things back to normal by adding a namespace-scope declaration… except we can’t directly in our case because vector is a class template. In fact you run into many pitfalls when you first dwell into class templates and friends—e.g. you might see this reasonable FAQ item and try to take advantage of it, only to discover it’s not applicable in the situation.
Not so inline
If you really do care about users naming advance outside of unqualified calls (e.g. to take an address or what have you), my advice is to 'disentangle' iterator from vector:
// might now need additional parameters for vector to fill in
template<typename Element>
struct vector_iterator;
template<typename Element, typename Allocator>
struct vector {
using iterator = vector_iterator<Element>;
…
};
In particular, if we follow the advice of the previous FAQ item we may end up with something of the form:
template<typename Element>
void advance(vector_iterator<Element> it, int n);
It is worth pointing out that this is obviously a function template, and it will be preferred over e.g. std::advance due to partial ordering rules. Partial ordering is nearly always my preferred approach to the matter.
I have a class named A, and in this class I have an iterable container, which I do iterate through following some rules of access -- order, emptiness, and others.
To simplify the following example, lets consider I'm just iterating through the container, but this cannot be done using the built-in container's iterator.
class A {
public:
class iterator {
public:
// Constructor
iterator() {
}
// Destructor
~iterator() {
}
// Advances the iterator
void operator++() {
// Some accessing policy
}
};
private:
std::vector<int> a;
};
Everything works tremendously fine -- and looks very neat --, except that, when I do declare my iterator, I must use typename -- which I pretty much assume that is used in order to tell the compiler that what I have is a type, and not a class instanciation itself.
Questions:
why do I have to use typename when I do:
A a;
for (typename A::iterator it(...); it != ...; ++it) {
}
How are iterators commonly defined, since a vector iterator does not require the typename tag? Does it have to do with declaring the vector from the class definition, instead of from the vector itself?
std::vector<int> v;
for (std::vector<int>::iterator it(v.begin()); it != v.end(); ++it) {
}
Are the iterators defined inside the container class -- I guess it's named composition --, or, if not, how is it iterators are added to the namespace of a class, like in:
std::vector<int>::iterator it;
1 - why do I have to use typename when I do: [...]
You do not have to use typename. The typename disambiguator is required inside a template when you are using a dependent, qualified type name. This Q&A on StackOverflow clarifies things. This:
A a;
typename a::iterator it; // ERROR!
Is illegal C++. Provided that A is not the name of a template parameter, you should just do:
A::iterator it;
If you are inside a template and A is the name of a template parameter, such as in:
template<typename A>
struct X
{
void foo()
{
typename A::iterator it;
// ^^^^^^^^
// This is necessary here!
}
};
Then you have to use typename to tell the compiler that what follows the :: is the name of a type.
2 - How are iterators commonly defined, since a vector iterator does not require the typename tag?
Again, it is not true that "a vector iterator does not require the typename tag". If you have an explicit specialization of that vector, such as in:
std::vector<int>::iterator it; // "typename" not required
Then typename is not required, as it wasn't required in A::iterator it. If you are inside a template as in the following case, however, it will be required:
template<typename A>
struct X
{
void foo()
{
typename std::vector<A>::iterator it;
// ^^^^^^^^
// This is necessary here!
}
};
That's because std::vector<A>::iterator here is a qualified, dependent type name.
3 - Are the iterators defined inside the container class -- I guess it's named composition --, or, if not, how is it iterators are added to the namespace of a class, like in [..]
This could be done by defining a nested class, or simply done by using type aliases:
template<typename T>
struct X
{
typedef T* iterator;
iterator begin() { /* ... */ }
// ...
};
X<int>::iterator it; // OK: "typename" not required
template<typename T>
void foo(X<T>& x)
{
typename X<T>::iterator it = x.begin();
// ^^^^^^^^
// This is necessary here!
// ...
}
There are a lot of problems with your example code, so this may be the answer you are looking for (waves hand) :) Of course if your examples are not correct, then all bets are off.
I'm surprised that this would work at all. 'a' is a variable, 'A' is the class.
Also, when declaring a variable with a default constructor, you do not use ending parenthesis ().
A a;
A::iterator it;
for (A::iterator it; it != ...; ++it) {
}
Also, iterators are defined within the container class. Using typename should only be necessary when you are dealing with templates and only when the accessing something that could be interpreted as either a static member or function/nested class or typedef. This can be further explained by the answer here which was also given by Andy Prowl.
Good luck
Is there any way to check if an arbitrary variable type is iterable?
So to check if it has indexed elements or I can actually loop over it's children? (Use foreach for example?)
Is it possible to create a universal template for that?
I've found techniques for other programming languages while searching for it. Yet still have to find out how to do this in C++.
You may create a trait for that:
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));
Live example.
cpprefence has an example answering your question. It is using SFINAE, here is a slightly modified version of that example (in case the content of that link gets changed over time):
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;
Now, this is how it can be used
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';
Output:
true
true
false
false
Having said that, all it checks is, the declaration of begin() const and end() const, so accordingly, even following is verified as an iterable:
struct Container
{
void begin() const;
void end() const;
};
std::cout << is_iterable_v<Container> << '\n'; // prints true
You can see these pieces together here
If you are under the umbrella of C++11 and beyond, one usual way of SFINAE checking that works when you have to specialize for just one property, is the following one:
template<class T, class = decltype(<expression that must compile>)>
inline constexpr bool expression_works(int) { return true; }
template<class>
inline constexpr bool expression_works(unsigned) { return false; }
template<class T, bool = expression_works<T>(42)>
class my_class;
template<class T>
struct my_class<T, true>
{ /* Implementation when true */ };
template<class T>
struct my_class<T, false>
{ /* Implementation when false */ };
The trick is as follow:
When the expression doesn't work, only the second specialization will be instantiated, because the first will fail to compile and sfinae plays out. So you get false.
When the expression works, both overloads are candidate, so I have to force a better specialization. In this case, 42 has type int, and thus int is a better match than unsigned, getting true.
I take 42 because it's the answer to everything, inspired by Eric Niebler's range implementation.
In your case, C++11 has the free functions std::begin and std::end that works for arrays and containers, so the expression that must work is:
template<class T, class = decltype(std::begin(std::declval<T>()))
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
If you need more generality, a way to express that something is iterable could also include user-defined types that brings their own overloads for begin and end, so you need to apply some adl here:
namespace _adl_begin {
using std::begin;
template<class T>
inline auto check() -> decltype(begin(std::declval<T>())) {}
}
template<class T, class = decltype(_adl_begin::check<T>())>
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
You can play with this technique to achieve solutions that fits better your actual context.
Yes using this traits class compatible 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) };
};
Explanation
check<C>(0) calls check(int,const_iterator) if C::end() exists and returns a const_iterator compatible type
else check<C>(0) calls check(...) (see ellipsis conversion)
sizeof(check<C>(0)) depends on the return type of these functions
finally, the compiler sets the constant value to true or false
See compilation and test run on coliru
#include <iostream>
#include <set>
int main()
{
std::cout <<"set="<< is_iterable< std::set<int> >::value <<'\n';
std::cout <<"int="<< is_iterable< int >::value <<'\n';
}
Output
set=1
int=0
Note: C++11 (and C++14) provides many traits classes but none about iterablility...
See also similar answers from jrok and Jarod42.
This answer is in Public Domain - CC0 1.0 Universal
It depends on what you mean by "iterable". It is a loose concept in C++ since you could implement iterators in many different ways.
If by foreach you're referring to C++11's range-based for loops, the type needs begin() and end() methods to be defined and to return iterators that respond to operator!=,
operator++ and operator*.
If you mean Boost's BOOST_FOREACH helper, then see BOOST_FOREACH Extensibility.
If in your design you have a common interface that all iterable containers inherit from, then you could use C++11's std::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
Or if (like me) you hate every SFINAE solution being a big block of dummy struct definitions with ::type and ::value nonsense to wade through, here's an example of using a quick and (very) dirty one-liner:
template <
class Container,
typename ValueType = decltype(*std::begin(std::declval<Container>()))>
static void foo(Container& container)
{
for (ValueType& item : container)
{
...
}
}
The last template argument does multiple things in one step:
Checks to see if the type has a begin() member function, or equivalent.
Checks that the begin() function returns something that has operator*() defined (typical for iterators).
Determines the type that results from de-referencing the iterator, and saves it in case it's useful in your template implementation.
Limitation: Doesn't double-check that there's a matching end() member function.
If you want something more robust/thorough/reusable, then go with one of the other excellent proposed solutions instead.