views:

1257

answers:

4

I'm having a really nasty problem with some code that I've written. I found someone else that had the same problem on stackoverflow and I tried the solutions but none worked for me.

I typedef several common STL types that I'm using and none of the others have any problem except when I try to typedef a map. I get a "some_file.h:83: error: expected initializer before '<' token" error when including my header in a test program.

Here's the important part of the header(some_file.h):

#ifndef SOME_FILE_H
#define SOME_FILE_H
// some syntax-correct enums+class prototypes
typedef std::string str;
typedef std::vector<Column> col_vec;
typedef col_vec::iterator col_vec_i;
typedef std::vector<Row> row_vec;
typedef row_vec::iterator row_vec_i;
typedef std::vector<str> str_vec;
typedef str_vec::iterator str_vec_i;
typedef std::vector<Object> obj_vec;
typedef obj_vec::iterator obj_vec_i;
typedef std::map<Column, Object> col_obj_map; // error occurs on this line
typedef std::pair<Column, Object> col_obj_pair;

The includes in some_file.cpp are:

#include <utility>
#include <map>
#include <vector>
#include <iostream>
#include <string>
#include <stdio.h>
#include <cc++/file.h>
#include "some_file.h"

The test file simply includes string, vector, and my file in that order. It has a main method that just does a hello world sort of thing.

The funny thing is that I quickly threw together a templated class to see where the problem was (replacing the "std::map<Column..." with "hello<Column...") and it worked without a problem.

I've already created the operator overload required by the map if you're using a class without a '<' operator.

+4  A: 

Is there a #include <map> somewhere in your header file?

Put that in there to at least see if it works. You should be doing that anyway.

GMan
+4  A: 

You should shift some of those includes into your header file. These need to be placed before your typedef statements.

i.e.

#include <map>
#include <string>
#include <map>

Otherwise, anything else including some_file.h (such as your main program) won't know what they are unless it also places these includes before the #include "some_file.h" include directive in your main program source file. If you do this, the problem should go away.

Matt H
Wow, can't believe I missed that! I usually include all the STL stuff in the main program anyway so this problem never cropped up. Thanks for pointing it out.
+10  A: 

You are getting this problem because the compiler doesn't know what a map is. It doesn't know because the map header hasn't been included yet. Your header uses the STL templates: string, vector, map, & pair. However, it doesn't define them, or have any reference to where they are defined. The reason your test file barfs on map and not on string or vector is that you include the string and vector headers before some_file.h so string and vector are defined, but map is not. If you include map's header, it will work, but then it may complain about pair (unless your particular STL implementation includes pair in map's header).

Generally, the best policy is to include the proper standard header for every type you use in your own header. So some_file.h should have, at least, these headers:

#include <string>
#include <map>
#include <utility> // header for pair
#include <vector>

The downside to this approach is that the preprocessor has to load each file every time and go through the #ifdef ... #endif conditional inclusion processing, so if you have thousands of files, and dozens of includes in each file, this could increase your compilation time significantly. However, on most projects, the added aggravation of having to manage the header inclusion manually is not worth the miniscule gain in compilation time. That is why Scott Meyers' Effective STL book has "Always #include the proper headers" as item #48.

A. Levy
Facepalm! I usually include the STL stuff in the program, not the header. Thanks for the link.
Now I know that I *should've* been including STL stuff in the header.
To speed up compilation on a big project, only put includes that relate to that header file in it. A corresponding source file will only need to include the header file and any extra files that relate to the source implementation in it.
Matt H
@Matt, that is true. However, you will still end up processing the same file multiple times in many cases. For example, if A.h, B.h, ... Z.h all #include <vector>, then and main.cpp includes all 26 headers from A to Z, then the compiler processes vector 26 times. If you take #include <vector> out of the headers and include it before them in main.cpp, then it will still compile correctly, and only #include <vector> once. However, you end up needing to manually manage the inclusion dependencies, so it is rarely worth doing that.
A. Levy
@Levy : you shouldn't be doing it like that. Use precompiled headers instead : they can give a tenfold increase in compilation speed.A great page on how to do it : http://www.cygnus-software.com/papers/precompiledheaders.html
Bill Kotsias
A: 

As several people have pointed out, the compiler isn't finding the definition for map. Since you appear to be including the map header, there's 2 other possible causes i can think of:

  1. Another header file called map is being loaded instead of the std map header. I think this is unlikely.
  2. Another header is #define'ing map to be something else.

One way to check for either is get your compiler to generate the post-processed file, i.e. the source file after it has been run through the C pre-processor but before it has been compiled. You should then be able to find your offending line and see if the map type has been replaced with something else. You should also be able to search back up the file and see what header the #include opulled in.

How you generate the post-processed file is compiler dependent - check the cmd-line flags in the docs for your compiler.

jon hanson
For gcc: use gcc -E to see the postprocessed file.
quark