3

I have a simple piece of code that is giving me a compiler error. I've had no issues compiling and running this in a windows environment under Visual Studio, but now under linux, using gcc, I am having problems. Note I am using gcc 4.4.5, and using the -std=c++0x directive.

This code snippet is in a header file, file_handling.h, which does include all the necessary libraries (vector, string, fstream, etc). The variable 'output_file' is a member of the LogFile object, and gets properly checked/instantiated/etc elsewhere. The code itself is trivially simple, which is why I am stumped:

template <typename T> void LogFile::put(std::string const & header, std::vector<T> const & data) {

  output_file << header << " " << std::scientific << data[0] << std::endl;

  for (std::vector<T>::const_iterator value = (data.begin()+1); value < data.end(); ++value) {
           output_file << *value << std::endl;
  }

}

The compiler states:

In file included from file_handling.cpp:2:
file_handling.h: In member function 'void LogFile::put(const std::string&, const std::vector<T, std::allocator<_Tp1> >&)':
file_handling.h:132: error: expected ';' before 'value'
file_handling.h:132: error: 'value' was not declared in this scope
make: *** [file_handling.o] Error 1

Why does gcc not see the in-situ declaration of 'value' as a const_iterator? I've tried the following as a sanity check:

template <typename T> void LogFile::put(std::string const & header, std::vector<T> const & data) {
  std::vector<T>::const_iterator value;
  output_file << header << " " << std::scientific << data[0] << std::endl;

  for (value = (data.begin()+1); value < data.end(); ++value) {
           output_file << *value << std::endl;
  }

}

And receive the exact same compiler report. Given this looks simple, and worked fine in Visual Studio, what am I missing or misunderstanding about gcc and/or a Linux environment?

Avacar
  • 87
  • 1
  • 7
  • I had assumed that vector would have pulled iterator in for me, since ::const_iterator is one of its properties, and it has always worked in Visual Studio. That said, i just added it to test your idea, and, unfortunately, that did not fix it. Good idea, though. – Avacar Sep 03 '12 at 03:39
  • Try cbegin() instead of begin(). begin() is not for const iterators. You'll also need cend() instead of end(). – Jason Iverson Sep 03 '12 at 03:49
  • really? [Cplusplus.com](http://www.cplusplus.com/reference/stl/vector/begin/) suggests that begin() can return a const iterator if needed. Anyway, I tried your suggestion, and it stll gave the same compiler error. – Avacar Sep 03 '12 at 03:58

1 Answers1

5

The correct form should be:

template <typename T> void LogFile::put(std::string const & header, std::vector<T> const & data) {

  output_file << header << " " << std::scientific << data[0] << std::endl;

  for (typename std::vector<T>::const_iterator value = (data.cbegin()+1); value != data.cend(); ++value) {
           output_file << *value << std::endl;
  }

}

Note the addition of typename, and the changes from begin() and end() to cbegin() and cend().

typename is required when you're using a templated type. begin() and end() are not for const_iterators.

Edit: Apparently begin() and end() will return const_iterators. I'd never used them for that purpose and always used cbegin() and cend() due to the added clarity and forced return types. To each his own I guess.

Note: To simplify, you can use the new auto keyword from c++11.

template <typename T> void LogFile::put(std::string const & header, std::vector<T> const & data) {

  output_file << header << " " << std::scientific << data[0] << std::endl;

  for (auto value = (data.cbegin()+1); value != data.cend(); ++value) {
           output_file << *value << std::endl;
  }

}
Jason Iverson
  • 2,500
  • 1
  • 15
  • 15
  • That seems to have solved it. So I guess Visual Studio was going easy on me, and assumed the typename keyword? I've used that syntax before and never needed it, but only on VS2010 versions of the code. Why is the typename keyword required? Why is it not clear that std::vector::const_iterator is a type? – Avacar Sep 03 '12 at 04:07
  • @Avacar: No, it's not clear, because of partial specialization. For example, if `T` were `bool`, things would get very weird very fast. – Ben Voigt Sep 03 '12 at 04:10
  • Ah, it's because of the template. If this had been std::vector::const_iterator or something similar, would it have the same need for typename? [This article](http://pages.cs.wisc.edu/~driscoll/typename.html) seems to be explaining it, as least within templated functions and classes. Was this because it was within a template, or because vector itself is a template? – Avacar Sep 03 '12 at 04:14
  • @Avacar: See [my previous question](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) – MSalters Sep 03 '12 at 07:18