1

In my code base, I 'hide' implementation details of heavily templated code in .tcc files inside a bits sub-directory, i.e.

// file inc/foo.h:
#ifndef my_foo_h          // include guard
#define my_foo_h
namespace my {
  /* ... */               // templated code available for user
}
#include "bits/foo.tcc"   // includes implementation details
namespace my {
  /* ... */               // more templated code using details from foo.tcc
}
#endif

// file inc/bits/foo.tcc:
#ifndef my_foo_tcc        // include guard
#define my_foo_tcc
#ifndef my_foo_h
#  error foo.tcc must be #included from foo.h
#endif
namespace my { namespace details {
  /* ... */               // defails needed in foo.h
} }
#endif

Of course, there must only be one file bits/foo.tcc in the include path. Otherwise, there will be a clash and (hopefully) a compilation error. This just happened to me with bits/vector.tcc, which is included from gcc's (4.8) vector but also my own header (using #include "bits/vector.tcc" and not #include <bits/vector.h>).

My question: is this formally a bug of gcc (since it uses a name bits/vector.tcc which is not protected by the standard) or correct, i.e. even formally my fault? If the latter, what names for header files are guaranteed to be okay to use?

(note I don't want to hear obvious advices of how to avoid this).


Edit The problem is that the header file vector provided by the standard library (shipped by the compiler) has a preprocessor directive #include <bits/vector.tcc> which causes the preprocessor to load my file rather than that provided with the standard library.

Walter
  • 44,150
  • 20
  • 113
  • 196
  • `#include bits/foo.tcc` should never compile, you need to surround the header name with `<>` or `""`. – Mankarse Jun 16 '14 at 09:15
  • Can you fix your example code to include the appropriate `" "` or `< >` delimiters in `#include` directives? It might actually be important which ones you use. – Angew is no longer proud of SO Jun 16 '14 at 09:16
  • 2
    *"Of course, there must only be one file bits/foo.tcc in the include path. Otherwise, there will be a clash and (hopefully) a compilation error."* Consult your compiler's documentation. That's not of the Standards concern. IIRC, you can have multiple files of the same name in different directories that are all searched, because there's a compiler-defined order to search those directories. – dyp Jun 16 '14 at 09:17
  • 1
    @dyp *That's not of the Standards concern* Do you mean that it is perfectly legal to `#include "vector"` but not intend the standard library header (as long as you sort the inclusion)? – Walter Jun 16 '14 at 09:46
  • 1
    @Angew using `<>` or `""` makes no difference. – Walter Jun 16 '14 at 09:47
  • @Walter re: `#include "vector"`. As far as the standard is concerned, that's certainly the case. `#include <>` is for including standard library headers. `#include ""` is for including everything else. – Angew is no longer proud of SO Jun 16 '14 at 09:49
  • @dyp If you can prove that the standard makes no statements regarding header files that would have any implication for this problem, than I'd be happy to accept that as an answer – Walter Jun 16 '14 at 09:49
  • @Angew See my edit: `#include ""` runs into the same problem. – Walter Jun 16 '14 at 09:50
  • 2
    @Angew [citation needed]. – rubenvb Jun 16 '14 at 09:52
  • @Walter: `<>` or `""` indeed *does* make a difference, as far as the standard is concerned. (None of the compilers I know of actually *makes* the distinction allowed by the standard, though.) – DevSolar Jun 16 '14 at 09:53
  • @rubenvb: [citation](http://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename) – DevSolar Jun 16 '14 at 09:55
  • @DevSolar [Here's](https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html) one compiler which treats them differently – nos Jun 16 '14 at 09:56
  • @nos: Actually I was thinking about the part where something included by `<>` need not actually be a *file* at all, but could be satisfied by the compiler internally. But yes, the search sequence might be different as well. Nice to see the GCC docs specifically referring to `<>` as being for system includes. – DevSolar Jun 16 '14 at 09:57
  • @rubenvb Citation in answer. – Angew is no longer proud of SO Jun 16 '14 at 10:10

2 Answers2

2

Here's what the C++11 standard [cpp.include] has to say about this:

1 A #include directive shall identify a header or source file that can be processed by the implementation.

2 A preprocessing directive of the form

# include < h-char-sequence> new-line

searches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header. How the places are specified or the header identified is implementation-defined.

3 A preprocessing directive of the form

# include " q-char-sequence" new-line

causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters. The named source file is searched for in an implementation-defined manner. If this search is not supported, or if the search fails, the directive is reprocessed as if it read

# include < h-char-sequence> new-line

with the identical contained sequence (including > characters, if any) from the original directive.

In other words, #include < > is intended for searching for headers only. A header is one of the things provided by the standard library. I say "things" because the standard doesn't specify what it is - it doesn't have to a file at all (although all compilers I know implement headers as files).

#include " " is intended for "everything else" - in terms of the standard, they're all "source files," although in general speech we usually refer to files intended for being #included as "header files." Also note that if no such source file is found, a (standard library) header will be searched for instead.

So, in your case:

  • The standard doesn't say anything about files like bits/vector.tcc; in fact, it doesn't say anything about any files. All of this falls under the "implementation-defined" heading as is thus up to your compiler and its documentation.

    At the same time (thanks to @JamesKanze for pointing this out in the comments), the standard clearly specifies what #include <vector> should do, and never mentions that it could depend on a file's presence or absence. So in this regard, gcc loading your bits/vector.tcc instead of its own is a gcc bug. If gcc loaded its own bits/vector.tcc instead of yours, it would be within its "implementation-defined" scope.

  • #include "vector" is primarily intended to include a source file named vector. However, if no such file is found, the effect is the same as including the standard header <vector> (which causes class template std::vector to be considered defined).

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 1
    Okay, but I still don't have an answer to my question. The problem does no arise from my `#include` directive, but from the directive `#include ` in file `vector` provided by the compiler. That directive causes my own file to be included rather than that intended by the library. – Walter Jun 16 '14 at 10:20
  • @Walter See the first bullet point in the answer. It's simply outside of the scope of the standard, and up to gcc and its documentation. – Angew is no longer proud of SO Jun 16 '14 at 10:21
  • 1
    @Angew Yes and no. The standard clearly defines the impact of `#include `; if that statement doesn't have the desired impact, regardless of the names of your files, the compiler is broken. Historically, this has been solved by having the compiler first look for includes in the directory of the file which does the include, regardless of all other options, etc. So if there is a `bits/vector.h` in the same directory as ``, this is the one `` should find. – James Kanze Jun 16 '14 at 11:34
0

The standard is pretty open, but... including <vector> should work; I don't see anything that authorizes it not to (provided you've done #include <vector>, and not #include "vector"), regardless of the names your personal includes.

More generally, the more or less universal algorithm for searching for a header is to first search in the directory which contains the file which does the include. This is done precisely to avoid the type of problems you have encountered. Not doing this (or not using some other mechanism to ensure that includes from standard headers find the file they're supposed to) is an error in the compiler. A serious one, IMHO. (Of course, the compiler may document that certain options introduce certain restrictions, or that you need to use certain options for it to behave in a standard manner. I don't think that g++ documents -I as being incompatible with the standard headers, but it does say that if you use -iquote, it shouldn't influence anything included using <...>.)

EDIT:

The second paragraph above really only applies to the "..." form of the include. #include <vector> should find the standard header, even if you have a file vector in the same directory as the file you are compiling.

In the absense of -I options, this works. Universally, however, the -I option adds the directory in the search lists for both types of include. The reason for this is that you, as a developer, will probably want to treat various third party libraries (e.g. X-Windows) as if they were part of the system as well. (I think Linux does put X-Windows as part of the system, putting its headers in /usr/include, but this wasn't the usual case in other Unices in the past.) So you use -I to specify them, as well as you're other include directories. And if you have a file vector in one of your other directories, it will "override" the system one.

This is clearly a flaw: if I recall correctly (but it's been some time), g++ at one time did have additional options to put a directory in the list for only one type of include. And in modern gcc/g++, there's -iquote (and -I-, which specifies that all of the earlier -I options are for the "..." includes only). These features are little used, however, because gcc/g++ is the only compiler which supported them.

Given all this, the gcc/g++ handling is probably the best you can hope for. And the error isn't in the compiler itself, but the library headers, which use <bits/vector.tcc> when it absolutely wants the include file from the same directory as the file doing the including. (Another way of saying this is that bits/vector.tcc isn't a system header, in any sense of the word, but an implementation header of system library.)

None of which helps the original poster much, unless he feels like modifying the library headers for g++. (If portability isn't any issue, and he's not considering his headers as part of the system, he could change the -I to -iquote.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • The [man page](http://linux.die.net/man/1/gcc) for gcc merely says that `-I` adds a directory to the head of the include search path (before system headers). Nothing is said about searching in the same directory as the file from which the `#include` comes. Do you have any references/quotations for the *more or less universal algorithm for searching for a header*? – Walter Jun 17 '14 at 18:06
  • The _more or less universal_ comes from having used a number of different compilers (more than 15 if you include C), and never having seen any other behavior. In the case of g++, it's documented in "https://gcc.gnu.org/onlinedocs/gcc-4.9.0/cpp/Search-Path.html#Search-Path" (which can be reached by following the "implementation defined behavior" links in the basic g++ documentation). More generally, however, this "universal behavior" really only applies to `#include "..."`; `#include ` should find the standard library header, even if you have a file named `vector` in your directory. – James Kanze Jun 18 '14 at 09:33
  • *`#include ` should find the standard library header, even if you have a file named `vector` in your directory* **No**, not if you `-I` the directory with your own file `vector`. – Walter Jun 19 '14 at 11:50
  • @Walter The standard says yes: §17.6.2.2: "The entities in the C++ standard library are defined in headers, whose contents are made available to a translation unit when it contains the appropriate #include preprocessing directive." No ifs, ands or buts. (But I suspect that most compilers are defective in this regard.) But the real issue in the OPs question is slightly different: if the compiler finds the standard header vector, then it should behave as the standard requires, regardless of the names of any of your files. – James Kanze Jun 19 '14 at 12:15
  • UPDATE: found this configuration option - will try it out... --with-local-prefix=dirname Specify the installation directory for local include files. The default is /usr/local. Specify this option if you want the compiler to search directory dirname/include for locally installed header files instead of /usr/local/include. You should specify --with-local-prefix only if your site has a different convention (not /usr/local) for where to put site-specific files. – user2465201 Sep 07 '18 at 13:45