Reputation: 13713
What do I have to write for YYY, ZZZ in order to set iterator_type
to the iterator type associated with T
? It should work in Visual Studio C++ 2010, if possible (but general standard solution is ok as well).
template<class T>
struct iterator_for {
typedef YYY<T>::ZZZ type;
}
Hence I want:
iterator_for<double[3]>::type is double *
iterator_for<std::string>::type is std::string::iterator
iterator_for<char[12]>::type is char *
etc.
I have a templated wrapper class Wrapper<T>
storing something iterable (i.e. a container or string or an array) and I want to define a function returning an iterator pointing into the wrapped object. For that purpose, I need to be able to speak about the iterator type corresponding to T
. For an array, the corresponding iterator would be a pointer, and for a string that is whatever string defines to be its iterator type.
Upvotes: 3
Views: 11010
Reputation: 585
My solution is:
typedef decltype(std::begin(std::declval<T&>())) type;
The iterator type is the type returned by std::begin
when called on an instance of T
. std::declval<T&>
is declared to return a T&
, on which we can call std::begin
.
This differs from JohnB's answer in that we pass a reference to the container type to std::begin
. This is needed because:
std::declval<T>()
returns an rvalue reference (T&&
).std::begin
takes its argument by non-const reference.std::declval<T&>
however returns an lvalue refernce because of reference collapsing.
Upvotes: 7
Reputation: 3765
The Boost library already has this:
#include <boost/range.hpp>
#include <iostream>
#include <string>
#include <vector>
template <typename T> void print_list(const T& container) {
typedef typename boost::range_iterator<const T>::type iter;
for (iter i = boost::begin(container); i != boost::end(container); ++i)
std::cout << *i << ";";
std::cout << "\n";
}
int main() {
double array[] = {1.0,2.0,3.0};
std::string str = "Hello";
std::vector<int> vec(3, 10);
print_list(array); // prints 1;2;3;
print_list(str); // prints H;e;l;l;o;
print_list(vec); // prints 10;10;10;
}
Upvotes: 1
Reputation: 92271
If you just want to separate containers from pointers, you can try this
template<class T>
struct iterator_for
{
typedef typename T::iterator type;
};
template<class T>
struct iterator_for<T*>
{
typedef T* type;
};
template<class T, std::size_t N>
struct iterator_for<T (&)[N]>
{
typedef T* type;
};
Upvotes: 4
Reputation: 13713
Ok, one possibility probably is (in C++11, but does not work in VS 2010):
typedef typename std::remove_reference<
decltype (
begin ( std::declval<T> () )
)
>::type
type;
Upvotes: 3