Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-05-07 19:55:20

Ian McCulloch <ianmcc_at_[hidden]> writes:

> David Abrahams wrote:
>> "Arkadiy Vertleyb" <vertleyb_at_[hidden]> writes:
>>> "David Abrahams" <dave_at_[hidden]> wrote
>>>> Any time a template is instantitated, all names in its definition
>>>> must map to the same entities in each translation unit, or you
>>>> violate the ODR. By definition, names in the unnamed namespace
>>>> refer to distinct entities in each translation unit.
> But typedef only introduces aliases for an existing type. Does that
> qualify for "map[s] onto the same entity" ?

Your question isn't specific enough for me to answer.

>>> IOW, such templates in different translation units will be
>>> absolutely the same, although in each translation unit the
>>> compiler will have to instantiate different intermediate classes
>>> in order to produce them.
> Those intermediate classes are in an unnamed namespace and not an ODR
> violation in themselves?

Not in and of themselves. Their use in the same template in multiple
translation units is a violation, IIUC.

> If I understand correctly, you are saying that
> // header.h
> namespace {
> typedef int foo;
> }
> struct bar { foo f; };
> // end header.h
> causes an ODR violation if type bar (or even foo) is used in more
> than one translation unit?

That appears to be clearly spelled out below. AFAICT unnamed namespaces in
header files are evil.

> Can you quote chapter and verse? (or perhaps that should be asked
> on c.s.c++).

Probably ;-) It's all there right under "One definition rule" in the

3 Basic concepts 3.2 One definition rule

-5- There can be more than one definition of a class type (clause
 class), enumeration type (dcl.enum), inline function with external
 linkage (dcl.fct.spec), class template (clause temp), non-static
 function template (temp.fct), static data member of a class template
 (temp.static), member function [core 249: template of a class
 template ] (temp.mem.func), or template specialization for which some
 template parameters are not specified (temp.spec, temp.class.spec) in
 a program provided that each definition appears in a different
 translation unit, and provided the definitions satisfy the following
 requirements. Given such an entity named D defined in more than one
 translation unit, then

   - each definition of D shall consist of the same sequence of
     tokens; and

   - in each definition of D, corresponding names, looked up according
     to basic.lookup, shall refer to an entity defined within the
     definition of D, or shall refer to the same entity, after
     overload resolution (over.match) and after matching of partial
     template specialization (temp.over), except that a name can refer
     to a const object with internal or no linkage if the object has
     the same integral or enumeration type in all definitions of D,
     and the object is initialized with a constant expression
     (expr.const), and the value (but not the address) of the object
     is used, and the object has the same value in all definitions of
     D; and

   - in each definition of D, the overloaded operators referred to,
     the implicit calls to conversion functions, constructors,
     operator new functions and operator delete functions, shall refer
     to the same function, or to a function defined within the
     definition of D; and

   - in each definition of D, a default argument used by an (implicit
     or explicit) function call is treated as if its token sequence
     were present in the definition of D; that is, the default
     argument is subject to the three requirements described above
     (and, if the default argument has sub-expressions with default
     arguments, this requirement applies recursively).*

[Footnote: dcl.fct.default describes how default argument names are
looked up. --- end foonote]

   - if D is a class with an implicitly-declared constructor
     (class.ctor), it is as if the constructor was implicitly defined
     in every translation unit where it is used, and the implicit
     definition in every translation unit shall call the same
     constructor for a base class or a class member of D.


      // translation unit 1:
      struct X {
          X(int, int);
      X::X(int = 0) { }
      class D: public X { };
      D d2; // X(int) called by D()

      // translation unit 2:
      struct X {
          X(int, int);
      X::X(int = 0, int = 0) { }
      class D: public X { }; // X(int, int) called by D();
                      // D()'s implicit definition
                      // violates the ODR

     --- end example]

   - If D is a template, and is defined in more than one translation
     unit, then the last four requirements from the list above shall
     apply to names from the template's enclosing scope used in the
     template definition (temp.nondep), and also to dependent names at
     the point of instantiation (temp.dep). If the definitions of D
     satisfy all these requirements, then the program shall behave as
     if there were a single definition of D. If the definitions of D
     do not satisfy these requirements, then the behavior is
     undefined. Point of instantiation 14 Templates

7 A specialization for a function template, a member function
template, or of a member function or static data member of a class
template may have multiple points of instantiations within a
translation unit. A special- ization for a class template has at most
one point of instantiation within a translation unit. A specialization
for any template may have points of instantiation in multiple
translation units. If two different points of instantiation give a
template specialization different meanings according to the one
definition rule (3.2), the program is ill-formed, no diagnostic

Dave Abrahams
Boost Consulting

Boost list run by bdawes at, gregod at, cpdaniel at, john at