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


757. Types without linkage in declarations

Section: 6.6  [basic.link]     Status: CD2     Submitter: John Spicer     Date: 23 December, 2008

[Voted into WP at July, 2009 meeting.]

Paper N2657, adopted at the June, 2008 meeting, removed the prohibition of local and unnamed types as template arguments. As part of the change, 6.6 [basic.link] paragraph 8 was modified to read,

A type without linkage shall not be used as the type of a variable or function with linkage, unless

Because a type without linkage can only be named as a dependent type, there are still some potentially useful things that cannot be done:

    template <class T> struct A {
      friend void g(A, T);  // this can't be defined later
      void h(T);  // this cannot be explicitly specialized
    };

    template <class T> void f(T) {
      A<T> at;
      g(at, (T)0);
    }

    enum { e };

    void g(A<decltype(e)>, decltype(e)){}  // not allowed

    int main() {
      f(e);
    }

These deficiencies could be addressed by allowing types without linkage to be used as the type of a variable or function, but with the requirement that any such entity that is used must also be defined in the same translation unit. This would allow issuing a compile-time, instead of a link-time, diagnostic if the definition were not provided, for example. It also seems to be easier to implement than the current rules.

Proposed resolution (March, 2009):

Change 6.6 [basic.link] paragraph 8 as follows:

...A type without linkage shall not be used as the type of a variable or function with linkage, unless

[Note: in other words, a type without linkage contains a class or enumeration that cannot be named outside its translation unit. An entity with external linkage declared using such a type could not correspond to any other entity in another translation unit of the program and thus is not permitted must be defined in the translation unit if it is used. Also note that classes with linkage may contain members whose types do not have linkage, and that typedef names are ignored in the determination of whether a type has linkage. —end note] [Example:

    void f() {
      struct A { int x; };    // no linkage
      extern A a;             // ill-formed
      typedef A B;
      extern B b;             // ill-formed
    }

end example]

[Example:

    template <class T> struct A {
      // in A<X>, the following is allowed because the type with no linkage
      // X is named using template parameter T.
      friend void f(A, T){}
    };

    template <class T> void g(T t) {
      A<T> at;
      f(at, t);
    }

    int main() {
      class X {} x;
      g(x);
    }


    template <typename T> struct B {
        void g(T){}
        void h(T);
        friend void i(B, T){}
    };

    void f() {
        struct A { int x; };  // no linkage
        A a = {1};
        B<A> ba;              // declares B<A>::g(A) and B<A>::h(A)
        ba.g(a);              // OK
        ba.h(a);              // error: B<A>::h(A) not defined in the translation unit
        i(ba, a);             // OK
    }

end example]

[Drafting note: issue 527 also changes part of the same text.]