0

I thought I was starting to get the hang of C++ ....

Then I wrote what I thought we are very simple templated function and all of a sudden it seems like nothing makes sense again. The compiler doesn't even seem to like the fact that I have defined a templated function, which seems a bit crazy. It is single unit of compilation so I am not sure what it would be complaining about.

#include <vector>
#include <iostream>

typedef std::vector<int> int_vec_type;

template <typename Type>
bool print_vec(Type::const_iterator itr, const Type::const_iterator end)
{
    for (; itr != end; ++itr) {
        std::cout << *itr << std::endl;
    }

    return true;
}

int
main()
{
    int_vec_type ivec;

    ivec.push_back(0);
    ivec.push_back(1);
    ivec.push_back(2);

    print_vec(ivec.begin(), ivec.end());

    return 0;
}

these are the compilation errors:

tia.cc:7:22: error: template declaration of ‘bool print_vec’

tia.cc:7:37: error: expected ‘)’ before ‘itr’

tia.cc:7:42: error: expected primary-expression before ‘const’

tia.cc: In function ‘int main()’:

tia.cc:25:39: error: ‘print_vec’ was not declared in this scope

thanks in advance.

user442585
  • 571
  • 1
  • 9
  • 17
  • 1
    http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords, but your function arguments don't match your function logic. – chris Sep 24 '12 at 20:18
  • @chris: That linked question, how is it related to this question? – David Rodríguez - dribeas Sep 24 '12 at 20:24
  • @DavidRodríguez-dribeas, It [*does* work](http://liveworkspace.org/code/9c7121b1135a6af838faadd7f6ea491c) with it in there and some help with the template argument, but of course taking the iterator as the template parameter is the proper solution. Either way, I thought the link would help the OP, at least when the situation inevitably arises and creates another dupe. – chris Sep 24 '12 at 20:33
  • @chris: That definition of *does work* is interesting... basically you are saying that if you explicitly name the type, then the compiler has no problem deducing it. Yes, that is correct. (As a side note, why do people like 'liveworkspace' so much? In both Safari and IE the fonts are painful to read when pretty-printing is enabled) – David Rodríguez - dribeas Sep 24 '12 at 20:49
  • @DavidRodríguez-dribeas, Yeah, it's not much of a solution compared to the best one, but I meant the OP's method can work if you do it the right way. About LWS (compared to Ideone, at least), I like it because a) The compiler is much more recent, b) The tabs only do three spaces instead of eight, c) I think there are more useful warnings turned on, and d) It lets me edit the code straight after compiling instead of going back, or copy-pasting if someone else posts a link. I suppose having boost is nice as well. I wasn't aware of the font issue; I've only ever used it with chrome. – chris Sep 24 '12 at 21:17

3 Answers3

6

The type of the container is not deducible from the type of the iterator. You can simply transform the template into:

template <typename Iterator>
bool print_vec(Iterator itr, const Iterator end)
{
    for (; itr != end; ++itr) {
        std::cout << *itr << std::endl;
    }

    return true;
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
3

First problem: You have not used typename. Wherever a type depends on a template argument, you must prefix the type with typename.

Secondly, the compiler cannot infer type. It can only see the type of ivec.begin() and has no idea about any other types that might have it as a typedef. You can only take the const_iterator directly- you can't take a T::const_iterator- without passing T explicitly, anyway.

Puppy
  • 144,682
  • 38
  • 256
  • 465
2

The best solution would be to template in terms of iterator types, since the container's type cannot be deduced from the function arguments:

template <typename Iterator>
bool print_vec(Iterator itr, Iterator end) { .... }
juanchopanza
  • 223,364
  • 34
  • 402
  • 480