The One-Definition Rule (C++)

The one-definition rule is specified in the C++ standard. The one-definition rule has two aspects:

  1. A translation unit must not contain more than one definition of any variable, function, class type, enumeration type, or template.
  2. External definitions must not be redefined within a program.

Traditional C++ compilers enforce only the first part of the one-definition rule. The incremental compiler enforces the full rule, to conform to the C++ standard and to remove the possibility of two or more conflicting definitions being visible at the same time during a build. As implemented in the incremental compiler, the one-definition rule means that declarations with external linkage cannot be defined in more than one source file. The one-definition rule allows some declarations, such as class and enum definitions, templates, and inline functions, to be defined in different source files as long as they consist of the same sequence of tokens. The incremental compiler accepts these multiple definitions.

Because the incremental compiler performs C++ builds in which all source files are considered at once, the one-definition rule applies to the set of C++ source files that are input to one build. As a result, the incremental compiler may not accept code that other compilers accept in some circumstances. The circumstances relate to following constructs and are described in detail below:

If your C++ sources are rejected by the incremental compiler due to the one-definition rule, you should consider using one of the following methods to correct the problem:

  1. Change the name of one of the conflicting definitions.
  2. Enclose the code that depends on each of the conflicting definitions in different namespaces.
  3. Split your source files so that each of the conflicting definitions is in a separate codestore. Do this by creating a separate configuration file in the same project. For example, you can build DLLs and your executable program from different configuration files.

If you specify the same source file more than once in your configuration file, the incremental compiler treats each occurrence of the file as a separate and unrelated source file. The one-definition rule limits the way you can reuse C++ source files in one codestore.

Classes, enums, Templates, and Inline Functions
The C++ language does not allow classes, enums, templates, and inline functions to be defined more than once in a program, unless all three of the following conditions are satisfied:

Traditional compilers test for the first condition. For example, they make sure that classes and enums are defined only once within a source file. the incremental compiler tests for the first two conditions and lets you redefine classes and enums only with definitions that are identical to the original definitions. Therefore, if a class or enum name is used with different definitions in different source files, the incremental compiler reports an error that traditional compilers do not find. While traditional compilers only check this rule within a source file, the incremental compiler checks it across all source files.

Enumerators and extern Variables
The C++ language allows only one definition of a given enumerator or variable name with external linkage in namespace scope, which includes global scope, and insists that multiple declarations of an external variable match. While traditional compilers only check this rule within a source file, the incremental compiler checks it across all source files.

typedef Statements
Standard C++ does not allow definitions with external linkage to be defined differently in different translation units. The incremental compiler applies this rule to types defined in typedef statements, which have no linkage according to standard C++. Unlike traditional compilers, the incremental compiler does not let you redefine a type with typedef statements in more than one source file unless the typedef statements are identical.

If the incremental compiler rejects a typedef statement in your C++ source because of the one-definition rule, you have an additional recovery technique to the three methods listed above. You can tell the incremental compiler to treat all typedef statements as local to the source file in which the type is defined, by building with option lang(localTypedefs, yes).


[Related Concepts]
Incremental C++ Builds
Codestore
Configuration Files
C++ Source Files and Source Regions

[Related Tasks]
Add or Change Source Files
Convert Included Source Files to Primary Source Files
Produce Multiple Targets from One Build