2

I'm trying to get a better knowledge about iterator_traits and found a snippet of code on a C++ textbook. So I've added some code to make it executable with the aim to understand the behaviour of that said compile-time mechanism. The complete program looks like so:

template<typename C>
    using Iterator_type = typename C::iterator;  

template<typename Iter>
    using Iterator_category = typename std::iterator_traits<Iter>::iterator_category;   

template<typename Ran>                                          
void sort_helper(Ran beg, Ran end, std::random_access_iterator_tag)   
{
    sort(beg, end);   
}

template<typename For>                                     
void sort_helper(For beg, For end, std::forward_iterator_tag)   
{
    std::vector<decltype(*beg)> v {beg, end};   
    sort(v.begin(), v.end());
    copy(v.begin(), v.end(), beg);              
}

template<typename C>
void sort(C& c)
{
    using Iter = Iterator_type<C>;
    sort_helper(c.begin(), c.end(), Iterator_category<Iter>{});
}

void test(std::vector<std::string>& v, std::forward_list<int>& lst)
{
    sort(v);     
    sort(lst);   
}

template<typename C>
void print(C& c)
{
    for(auto it = c.begin(); it != c.end(); ++it) {
        std::cout << *it << '\n';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<std::string> v { "Bicycle", "Hoovercraft", "Rocket", "Airplaine", "Bus", "Submarine" };
    print(v);

    sort(v);
    print(v);

    std::forward_list<int> lst { 2, 81, 3, 0, 4, 34, 23, 11 };
    print(lst);

    sort(lst);
    print(lst);

    return 0;
} 

The compilation fails telling that a pointer to reference is given:

memory:1723:16: error: 
  'pointer' declared as a pointer to a reference of type 'int &'
typedef _Tp*              pointer;

and the error stack brings to the following line:

in instantiation of template class 'std::__1::vector<int &,     std::__1::allocator<int &> >'
  requested here
std::vector<decltype(*beg)> v {beg, end};

this compiling either on Mac OS and on a Linux machine with g++.

I managed it to work modifying the involved part like so:

auto i = *beg;
std::vector<decltype(i)> v {beg, end};

Can you please give me a clearer explanation on why the decltype() function is returning a pointer to a reference? I've read some other questions regarding the decltype type function on SO and also have read the specifications but neither brought me on the right path, nor examining the full compiler stack of output messages was of any help.

Thank you in advance for any consideration.

wiredolphin
  • 1,431
  • 1
  • 18
  • 26
  • 2
    `decltype` yields a reference however the real error is that you are trying to build a vector of references `std::vector` which ultimately leads to appearance of pointers to references. – user7860670 Aug 31 '17 at 11:34
  • @VTT, yes that was clear enough. What is less obvious is if it was a mistake of the book's author (Bjarne Stroustrup) or am I missing something else? – wiredolphin Aug 31 '17 at 11:41
  • 1
    If this is in the book, it makes assumptions about the nature of the iterator's deferenced type that don't hold. See @LogicStuff 's answer, below. – dhke Aug 31 '17 at 11:49
  • 1
    Well, nobody is perfect, Bjarne Stroustrup definitely could've avoided several big mistakes in the past. And one can easily overlook a little defects like this one in book code snippets. – user7860670 Aug 31 '17 at 11:50

1 Answers1

2

The problem is that the decltype yields a reference type (you cannot make std::vector of).
Why is that so is answered here in-depth.

You can fix it by either of the two ways:

  • use std::remove_reference<decltype(*beg)>::type
  • use std::iterator_traits<For>::value_type
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
  • 1
    Both `std::vector::type> v {beg, end};` and `std::vector::value_type> v {beg, end};` gives a better explanation. – wiredolphin Aug 31 '17 at 11:53