Sun Studio 12 Update 1: C++ User's Guide

Chapter 5 Program Organization

The file organization of a C++ program requires more care than is typical for a C program. This chapter describes how to set up your header files and your template definitions.

5.1 Header Files

Creating an effective header file can be difficult. Often your header file must adapt to different versions of both C and C++. To accommodate templates, make sure your header file is tolerant of multiple inclusions (idempotent).

5.1.1 Language-Adaptable Header Files

You might need to develop header files for inclusion in both C and C++ programs. However, Kernighan and Ritchie C (K&R C), also known as “classic C,” ANSI C, Annotated Reference Manual C++ (ARM C++), and ISO C++ sometimes require different declarations or definitions for the same program element within a single header file. (See the C++ Migration Guide for additional information on the variations between languages and versions.) To make header files acceptable to all these standards, you might need to use conditional compilation based on the existence or value of the preprocessor macros __STDC__ and __cplusplus.

The macro __STDC__ is not defined in K&R C, but is defined in both ANSI C and C++. Use this macro to separate K&R C code from ANSI C or C++ code. This macro is most useful for separating prototyped from nonprototyped function definitions.


#ifdef __STDC__
int function(char*,...);      // C++ & ANSI C declaration
#else
int function();               // K&R C
#endif

The macro __cplusplus is not defined in C, but is defined in C++.


Note –

Early versions of C++ defined the macro c_plusplus instead of __ cplusplus. The macro c_plusplus is no longer defined.


Use the definition of the __cplusplus macro to separate C and C++. This macro is most useful in guarding the specification of an extern “C” interface for function declarations, as shown in the following example. To prevent inconsistent specification of extern “C”, never place an #include directive within the scope of an extern “C” linkage specification.


#include “header.h”
...                     // ... other include files...
#if defined(__cplusplus)
extern “C” {
#endif
  int g1();
  int g2();
  int g3()
#if defined(__cplusplus)
}
#endif

In ARM C++, the __cplusplus macro has a value of 1. In ISO C++, the macro has the value 199711L (the year and month of the standard expressed as a long constant). Use the value of this macro to separate ARM C++ from ISO C++. The macro value is most useful for guarding changes in template syntax.


// template function specialization
#if __cplusplus < 199711L
int power(int,int);                       // ARM C++
#else
template <> int power(int,int);           // ISO C++
#endif

5.1.2 Idempotent Header Files

Your header files should be idempotent. That is, the effect of including a header file many times should be exactly the same as including the header file only once. This property is especially important for templates. You can best accomplish idempotency by setting preprocessor conditions that prevent the body of your header file from appearing more than once.


#ifndef HEADER_H
#define HEADER_H
/* contents of header file */
#endif

5.2 Template Definitions

You can organize your template definitions in two ways: with definitions included and with definitions separated. The definitions-included organization allows greater control over template compilation.

5.2.1 Template Definitions Included

When you put the declarations and definitions for a template within the file that uses the template, the organization is definitions-included. For example:

main.cc


template <class Number> Number twice(Number original);
template <class Number> Number twice(Number original )
    { return original + original; }
int main()
    { return twice<int>(-3); }

When a file using a template includes a file that contains both the template’s declaration and the template’s definition, the file that uses the template also has the definitions-included organization. For example:

twice.h


#ifndef TWICE_H
#define TWICE_H
template <class Number>
Number twice(Number original);
template <class Number> Number twice( Number original )
    { return original + original; }
#endif

main.cc


#include “twice.h”
int main()
    { return twice(-3); }

Note –

It is very important to make your template headers idempotent. (See 5.1.2 Idempotent Header Files.)


5.2.2 Template Definitions Separate

Another way to organize template definitions is to keep the definitions in template definition files, as shown in the following example.

twice.h


#ifndef TWICE_H
#define TWICE_H
template <class Number>
Number twice(Number original);
#endif TWICE_H

twice.cc


template <class Number>
Number twice( Number original )
    { return original + original; }

main.cc


#include “twice.h”
int main( )
    { return twice<int>( -3 ); }

Template definition files must not include any non-idempotent header files and often need not include any header files at all. (See 5.1.2 Idempotent Header Files.) Note that not all compilers support the definitions-separate model for templates.

Because a separate definitions file is a header file, it might be included implicitly in many files. It therefore should not contain any function or variable definitions, unless they are part of a template definition. A separate definitions file can include type definitions, including typedefs.


Note –

Although source-file extensions for template definition files are commonly used (that is, .c, .C, .cc, .cpp, .cxx, or .c++), template definition files are header files. The compiler includes them automatically if necessary. Template definition files should not be compiled independently.


If you place template declarations in one file and template definitions in another file, you have to be very careful how you construct the definition file, what you name it, and where you put it. You might also need to identify explicitly to the compiler the location of the definitions. Refer to 7.5 Template Definition Searching” for information about the template definition search rules.