Incomplete type as template argument

Discussion in 'C++' started by Andrew Ward, Feb 25, 2004.

  1. Andrew Ward

    Andrew Ward Guest

    Hi All,

    Considering the following code:

    struct A;

    struct B
    {
    std::list<A> l;
    };

    void foo()
    {
    B b;
    };

    struct A
    {
    int x;
    };

    int main()
    {
    foo();
    A a;
    a.x = 22;
    B b;
    b.l.push_back(a);
    cout << "A's value = " << b.l.begin()->x << endl;
    }

    I do not understand why the compiler does not complain when encountered with std::list<A>
    when A has not been fully defined.
    Could someone please explain to me when the compiler actually does the template expansion,
    and is this method of using incomplete types as template arguments safe for all compliant
    compilers?

    Andy
    Andrew Ward, Feb 25, 2004
    #1
    1. Advertising

  2. "Andrew Ward" <> wrote...
    > Hi All,
    >
    > Considering the following code:
    >
    > struct A;
    >
    > struct B
    > {
    > std::list<A> l;


    Neither 'std' nor 'list' is defined.

    > };
    >
    > void foo()
    > {
    > B b;
    > };
    >
    > struct A
    > {
    > int x;
    > };
    >
    > int main()
    > {
    > foo();
    > A a;
    > a.x = 22;
    > B b;
    > b.l.push_back(a);
    > cout << "A's value = " << b.l.begin()->x << endl;
    > }
    >
    > I do not understand why the compiler does not complain when encountered

    with std::list<A>
    > when A has not been fully defined.


    I do not understand either. Comeau C++ does complain.

    > Could someone please explain to me when the compiler actually does the

    template expansion,
    > and is this method of using incomplete types as template arguments safe

    for all compliant
    > compilers?


    You should probably ask whoever made your compiler. They must hold
    the secret of how to use an incomplete type as a template argument...

    Victor
    Victor Bazarov, Feb 25, 2004
    #2
    1. Advertising

  3. "Andrew Ward" <> wrote in message
    news:hVV_b.1464$...
    > Hi All,
    >
    > Considering the following code:
    >


    <snip>


    > I do not understand why the compiler does not complain when

    encountered with std::list<A>
    > when A has not been fully defined.
    > Could someone please explain to me when the compiler actually does

    the template expansion,
    > and is this method of using incomplete types as template arguments

    safe for all compliant
    > compilers?


    This topic has been extensively discussed on comp.lang.c++.moderated
    recently. (See "class definition containing member of own type",
    etc. )

    According to the language rules, it may well be possible to
    instantiate std::list with an incomplete type (depending on the
    implementation.) However, the library requirements specifically make
    it undefined behaviour to instantiate a standard library template with
    an incomplete type (17.4.3.6).

    Presumably this will change, since one of the benefits of shared_ptr
    is supposed to be that it can be instantiated with an incomplete type.
    (I don't see anything about this in the TR1 draft, though.)

    Jonathan
    Jonathan Turkanis, Feb 25, 2004
    #3
  4. Andrew Ward

    Sharad Kala Guest

    "Andrew Ward" <> wrote in message
    news:hVV_b.1464$...
    > Hi All,
    >
    > Considering the following code:
    >
    > struct A;
    >
    > struct B
    > {
    > std::list<A> l;
    > };
    >
    > void foo()
    > {
    > B b;
    > };
    >
    > struct A
    > {
    > int x;
    > };
    >
    > int main()
    > {
    > foo();
    > A a;
    > a.x = 22;
    > B b;
    > b.l.push_back(a);
    > cout << "A's value = " << b.l.begin()->x << endl;
    > }


    Which compiler?
    Atleast VC 7, g++ 3.3.1 and Comeau online reject this code.

    -Sharad
    Sharad Kala, Feb 25, 2004
    #4
  5. Andrew Ward

    John Carson Guest

    "Sharad Kala" <> wrote in message
    news:c1hbg4$1h1eih$-berlin.de
    > "Andrew Ward" <> wrote in message
    > news:hVV_b.1464$...
    >> Hi All,
    >>
    >> Considering the following code:
    >>
    >> struct A;
    >>
    >> struct B
    >> {
    >> std::list<A> l;
    >> };
    >>
    >> void foo()
    >> {
    >> B b;
    >> };
    >>
    >> struct A
    >> {
    >> int x;
    >> };
    >>
    >> int main()
    >> {
    >> foo();
    >> A a;
    >> a.x = 22;
    >> B b;
    >> b.l.push_back(a);
    >> cout << "A's value = " << b.l.begin()->x << endl;
    >> }

    >
    > Which compiler?
    > Atleast VC 7, g++ 3.3.1 and Comeau online reject this code.
    >
    > -Sharad



    VC++ 7.1 accepts it.


    --
    John Carson
    1. To reply to email address, remove donald
    2. Don't reply to email address (post here instead)
    John Carson, Feb 25, 2004
    #5
  6. Andrew Ward

    John Carson Guest

    "Victor Bazarov" <> wrote in message
    news:g5W_b.54098$Xp.257962@attbi_s54
    > "Andrew Ward" <> wrote...
    >> Hi All,
    >>
    >> Considering the following code:
    >>
    >> struct A;
    >>
    >> struct B
    >> {
    >> std::list<A> l;

    >
    > Neither 'std' nor 'list' is defined.
    >
    >> };
    >>
    >> void foo()
    >> {
    >> B b;
    >> };
    >>
    >> struct A
    >> {
    >> int x;
    >> };
    >>
    >> int main()
    >> {
    >> foo();
    >> A a;
    >> a.x = 22;
    >> B b;
    >> b.l.push_back(a);
    >> cout << "A's value = " << b.l.begin()->x << endl;
    >> }
    >>
    >> I do not understand why the compiler does not complain when
    >> encountered with std::list<A> when A has not been fully defined.

    >
    > I do not understand either. Comeau C++ does complain.
    >
    >> Could someone please explain to me when the compiler actually does
    >> the template expansion, and is this method of using incomplete types
    >> as template arguments safe for all compliant compilers?

    >
    > You should probably ask whoever made your compiler. They must hold
    > the secret of how to use an incomplete type as a template argument...
    >
    > Victor



    I don't claim to understand all the subtleties of this matter but... section
    14.3.1 p2 of the 2003 standard says:

    "[Note: a template type argument may be an incomplete type (3.9). ]"


    --
    John Carson
    1. To reply to email address, remove donald
    2. Don't reply to email address (post here instead)
    John Carson, Feb 25, 2004
    #6
  7. Andrew Ward

    Andrew Ward Guest

    "Sharad Kala" <> wrote in message
    news:c1hbg4$1h1eih$-berlin.de...
    >
    > "Andrew Ward" <> wrote in message
    > news:hVV_b.1464$...
    > > Hi All,
    > >
    > > Considering the following code:
    > >
    > > struct A;
    > >
    > > struct B
    > > {
    > > std::list<A> l;
    > > };
    > >
    > > void foo()
    > > {
    > > B b;
    > > };
    > >
    > > struct A
    > > {
    > > int x;
    > > };
    > >
    > > int main()
    > > {
    > > foo();
    > > A a;
    > > a.x = 22;
    > > B b;
    > > b.l.push_back(a);
    > > cout << "A's value = " << b.l.begin()->x << endl;
    > > }

    >
    > Which compiler?
    > Atleast VC 7, g++ 3.3.1 and Comeau online reject this code.
    >
    > -Sharad
    >
    >


    I am using VC 7.1, I am guessing from the responses though that this kind of code is not a
    good idea for compatibility with other compilers. The reason I wanted to do this was
    because I am trying to reduce the number of #includes in my header files, as to speed up
    compiles when changes are made to the headers.
    Andrew Ward, Feb 25, 2004
    #7
  8. Andrew Ward

    tom_usenet Guest

    On Wed, 25 Feb 2004 17:55:12 +1300, "Andrew Ward" <>
    wrote:

    >Hi All,
    >
    >Considering the following code:
    >

    [SNIP list<incomplete> example]
    >
    >I do not understand why the compiler does not complain when encountered with std::list<A>
    >when A has not been fully defined.
    >Could someone please explain to me when the compiler actually does the template expansion,
    >and is this method of using incomplete types as template arguments safe for all compliant
    >compilers?


    In general it is undefined behaviour to instantiate any standard
    container type with an incomplete type parameter. However, it has also
    been shown that an implementation of the standard library can
    carefully be written so that it will work with an incomplete type -
    the main things to do are to no have any nested types, e.g. make
    vector::iterator a typedef for a non-nested type.

    To understand why, you need to know a little bit about implicit
    instantiation. A class template specialization isn't instantiated
    until it is used in a context that requires a completely defined
    object type. So:

    typedef mytemplate<int> t; //no instantiation
    mytemplate<int> t; //no instantiation
    sizeof(mytemplate<int>); //instantiation
    mytemplate<int> t; //instantiation, possibly also of default
    constructor

    Now, when a class template definition is instantiated, any types that
    need to be complete in the class definition are also instantiated.
    e.g.

    template <class T>
    struct Foo
    {
    Bar<T> bar; //member, so instantiated
    Baz<T>* baz; //pointer, so not instantiated
    class Inner //member, so instantated
    {
    char array[sizeof(Baz<T>)]; //Baz<T> instantiated
    };
    };


    So once you understand those rules, consider how std::list might be
    implemented (ignoring the allocator parameter)

    template <class T>
    class list
    {
    struct Node
    {
    //boom, requires T to be complete
    //when list<T> is instantiated
    T value;
    Node* prior;
    Node* next;
    };
    //...
    };

    If you take the node type out, then you have:

    template <class T>
    struct ListNode
    {
    T value;
    ListNode* prior;
    ListNode* next;
    };

    template <class T>
    class list
    {
    //doesn't instantiate ListNode<T> when list<T> is instaniated
    typedef ListNode<T> node_t;
    //doesn't instantiate ListNode<T>
    node_t* node;
    //... etc
    };

    GCC allows use of all containers with incomplete types. Dinkumware
    have finally updated their library to do the same, and VC7.1 benefits.
    Many other compilers (including earlier versions of MSVC) don't allow
    incomplete types. Perhaps a future standard will guarantee that
    containers can be instantiated with incomplete types, but don't hold
    your breath.

    Tom
    --
    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    tom_usenet, Feb 25, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mikhail N. Kupchik
    Replies:
    4
    Views:
    3,138
    Jonathan Turkanis
    Sep 15, 2004
  2. verec
    Replies:
    2
    Views:
    1,003
    verec
    Jun 25, 2005
  3. Replies:
    13
    Views:
    801
    Greg Comeau
    Oct 2, 2006
  4. nw
    Replies:
    0
    Views:
    296
  5. Ryan Dupuis
    Replies:
    8
    Views:
    1,201
    Eric Sosman
    Oct 2, 2013
Loading...

Share This Page