This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 110b. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2023-01-15


370. Can #include <...> form be used other than for standard C++ headers?

Section: 15.3  [cpp.include]     Status: CD1     Submitter: Beman Dawes     Date: 01 August 2002

[Voted into WP at the October, 2006 meeting.]

The motivation for this issue is a desire to write portable programs which will work with any conforming implementation.

The C++ Standard (15.3 [cpp.include]) provides two forms of #include directives, with the <...> form being described (15.3 [cpp.include] paragraph 2) as "for a header", and the "..." form (15.3 [cpp.include] paragraph 3) as for "the source file" identified between the delimiters. When the standard uses the term "header", it often appears to be limiting the term to apply to the Standard Library headers only. Users of the standard almost always use the term "header" more broadly, to cover all #included source files, but particularly those containing interface declarations.

Headers, including source files, can be categorized according to their origin and usage:

  1. C++ Standard Library headers (which aren't necessarily files).
  2. Other standard libraries such as the POSIX headers.
  3. Operating system API's such as windows.h.
  4. Third party libraries, such as Boost, ACE, or commercial offerings.
  5. Organization-wide "standard" header files, such as a company's config.hpp.
  6. A project's "public" header files, often shared by all developers working on the same project.
  7. A project or user's "private", "local", or "detail" headers, in the same directory or sub-directory as the compilation unit.

Existing practice varies widely, but it is fairly easy to find users advocating:

Do any of the practices A, B, or C result in programs which can be rejected by a conforming implementation?

The first defect is that readers of the standard have not been able to reach consensus on the answers to the above question.

A second possible defect is that if A, B, or C can be rejected by a conforming implementation, then the standard should be changed because would mean there is a wide variance between the standard and existing practice.

Matt Austern: I really only see two positions:

  1. Implementations have some unspecified mechanism (copying files to a magic directory, adding a magic flag,...) such that the line #include <foo> results in textual inclusion of the file foo.
  2. Implementations are not required to have any mechanism for getting #include <foo> to perform textual inclusion of an arbitrary file foo. That form is reserved for standard library headers only.

I agree that the standard should clarify which of those two is the case (I imagine it'll hinge on finding one crucual sentence that either says "implementation defined" or "unspecified"), but from the standpoint of portability I don't see much difference between the two. I claim that, with either of those two interpretations, using #include <foo> is already nonportable.

(Of course, I claim that almost anything having to do with headers, including the #include "foo" form, is also nonportable. In practice there's wide variation in how compilers handle paths, especially relative paths.)

Beman Dawes: The whole issue can be resolved by replacing "header" with "header or source file" in 15.3 [cpp.include] paragraph 2. That will bring the standard into alignment with existing practice by both users and implementations. The "header and/or source file" wording is used at least three other places in the standard where otherwise there might be some confusion.

John Skaller: In light of Andrew Koenig's comments, this doesn't appear to be the case, since the mapping of include names to file names is implementation defined, and therefore source file inclusion cannot be made portable within the ISO C/C++ standards (since that provision obviously cannot be removed).

A possible idea is to create a binding standard, outside the C/C++ ISO Standards, which specifies not only the path lookup mechanism but also the translation from include names to file names. Clearly that is OS dependent, encoding dependent, etc, but there is no reason not to have a binding standard for Unix, Windows, etc, and specify these bindings in such a way that copying directories from one OS to the other can result in programs working on both OS's.

Andy Koenig: An easier solution might be to specify a (presumably unbounded, or bounded only by implementation capacity) collection of header-file names that every implementation must make it possible for programs to access somehow, without specifying exactly how.

Notes from October 2002 meeting:

This was discussed at some length. While there was widespread agreement that such inclusion is inherently implementation-dependent, we agreed to try to add wording that would make it clear that implementations are permitted (but not required) to allow inclusion of files using the <...> form of #include.

Proposed resolution (April, 2005):

Change 15.3 [cpp.include] paragraph 7 from:

[Example: The most common uses of #include preprocessing directives are as in the following:
    #include <stdio.h>
    #include "myprog.h"
end example]

to:

[Note: Although an implementation may provide a mechanism for making arbitrary source files available to the < > search, in general programmers should use the < > form for headers provided with the implementation, and the " " form for sources outside the control of the implementation. For instance:
    #include <stdio.h>
    #include <unistd.h>
    #include "usefullib.h"
    #include "myprog.h"
end note]

Notes from October, 2005 meeting:

Some doubt was expressed as to whether the benefit of this non-normative clarification outweighs the overall goal of synchronizing clause 16 with the corresponding text in the C99 Standard. As a result, this issue is being left in “review” status to allow further discussion.

Additional notes (October, 2006):

WG14 takes no position on this change.