8

In C++98, I typically use the following to declare a variable in an iterator's value type:

typename std::iterator_traits<Iterator>::value_type value;

In C++11 we have decltype and I had thought the easiest way to deduce the value type is:

decltype(*iterator) value;

Unfortunately for most iterators, the type of *iterator is value_type& and not value_type. Any ideas, without the type modification classes, how to massage the above into yielding the value_type (and not any reference)?


I don't think the question is unreasonable given that the following is fairly robust but ends up creating another variable.

auto x = *iterator;
decltype(x) value;

Also note that I really want the deduced type and not just an instance e.g. if I wanted to declare a std::vector of these values.

Glen Low
  • 4,379
  • 1
  • 30
  • 36
  • The type of the expression `*iterator` is `std::iterator_traits::reference`, not `value_type`. This is not necessarily `value_type&`, and `decltype` may report the type of an expression differently than it actually is depending on its value category. – Luc Danton Mar 22 '13 at 05:42
  • If you *just* want to combine the two lines of your edit, the equivalent would be `typename std::decay::type value;`, but check out the answer below and just don't do it :) I'm just adding this as [`std::decay`](http://en.cppreference.com/w/cpp/types/decay) wasn't mentioned in this Q/A before. – Daniel Frey Mar 22 '13 at 07:47

2 Answers2

17

Keep using iterator_traits. decltype(*iterator) could even be some sort of weird proxy class in order to do special things in the expression *iter = something.

Example:

#include <iostream>
#include <iterator>
#include <typeinfo>
#include <vector>

template <typename T>
void print_type()
{
    std::cout << typeid(T).name() << std::endl;
}

template <typename Iterator>
void test(Iterator iter)
{
    typedef typename
        std::iterator_traits<Iterator>::value_type iter_traits_value;

    auto x = *iter;
    typedef decltype(x) custom_value;

    print_type<iter_traits_value>();
    print_type<custom_value>();
}

int main()
{
    std::vector<int> a;
    std::vector<bool> b;

    test(a.begin());
    test(b.begin());
}

Output on MSVC 2012:

int
int
bool
class std::_Vb_reference<struct std::_Wrap_alloc<class std::allocator<unsigned int>>>

They aren't the same.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • But as I mention in my edit, the following works: auto x = *iterator; decltype(x) value; – Glen Low Mar 22 '13 at 01:18
  • 3
    @GlenLow: You haven't defined "works". See my edit to the answer (aschepler, edit as you please). – GManNickG Mar 22 '13 at 01:33
  • Ah... apologies @GManNickG and aschepler, you are both right, my given expression does not necessarily yield the same type as the iterator_traits expression. I was thinking perhaps forcing a lvalue-to-rvalue conversion inside of the decltype() would make it work identically to the iterator_traits expression, but for the life of me I can't figure out the expression. – Glen Low Mar 22 '13 at 02:31
  • 1
    `std::iterator_traits` is specialized for some kinds of iterators: there is no simple expression that matches that it does, and no simple expression that can match what it will do after someone else adds a specialization (that doesn't boil down to just using `std::iterator_traits`). – Yakk - Adam Nevraumont Mar 22 '13 at 13:52
1

For this use-case i like std::decay. Typicall i'd be using

std::vector< int > vec;
using value_type = typename std::decay< decltype(*begin(vec)) >::type; 
static_assert(std::is_same< int, value_type >::value, "expected int");
Martin Wirth
  • 153
  • 1
  • 6
  • Thanks for the suggestion, it does work (and I've learnt something new!) but it is not less verbose than `std::iterator_traits::value_type` when I already have the type of the Iterator. – Glen Low Mar 23 '13 at 04:23
  • true. iterator_traits<> are the way to go. I'm actually using my suggestion more when i have, for example, an unknown container type. if you have the iterator type already, you're definitely right. – Martin Wirth Mar 23 '13 at 20:52
  • I should note that this expression may not work where the reference type of the iterator is some perverse proxy, as in the `std::vector` specialization noted above. – Glen Low Mar 25 '13 at 00:03