Forward Declarations of types used in template container classes

Discussion in 'C++' started by Stephen Howe, Apr 8, 2011.

  1. Stephen Howe

    Stephen Howe Guest

    Hi

    I cant find whether this is valid C++, but I believe it is

    // ---------------------------- start header file
    #include <vector>

    // Forward Declaration
    class FooBar;

    int SomeFunction1(FooBar); // Valid
    declaration, I know this
    int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    using std::vector???

    // ---------------------------- end header file

    Yes FooBar is incomplete but all I am interested in is whether it is a
    valid declaration.
    All of this is to minimise header file dependency, so FooBar's
    definition is not dragged in.
    I know that where SomeFunction2 is defined, a full definition of
    FooBar is needed.

    Thanks

    Stephen Howe
     
    Stephen Howe, Apr 8, 2011
    #1
    1. Advertising

  2. On 4/8/2011 5:31 PM, Stephen Howe wrote:
    > Hi
    >
    > I cant find whether this is valid C++, but I believe it is
    >
    > // ---------------------------- start header file
    > #include<vector>
    >
    > // Forward Declaration
    > class FooBar;
    >
    > int SomeFunction1(FooBar); // Valid
    > declaration, I know this
    > int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    > using std::vector???
    >
    > // ---------------------------- end header file
    >
    > Yes FooBar is incomplete but all I am interested in is whether it is a
    > valid declaration.
    > All of this is to minimise header file dependency, so FooBar's
    > definition is not dragged in.
    > I know that where SomeFunction2 is defined, a full definition of
    > FooBar is needed.


    Since in the context of the declaration of 'SomeFunction2' the full
    definition of 'std::vector<FooBar>' is not required, it is not going to
    be instantiated. If no instantiation happens, FooBar may be incomplete.
    The declaration of 'SomFunction2' is legal, I suppose.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 8, 2011
    #2
    1. Advertising

  3. Stephen Howe

    Noah Roberts Guest

    On 4/8/2011 2:31 PM, Stephen Howe wrote:
    > Hi
    >
    > I cant find whether this is valid C++, but I believe it is
    >
    > // ---------------------------- start header file
    > #include<vector>
    >
    > // Forward Declaration
    > class FooBar;
    >
    > int SomeFunction1(FooBar); // Valid
    > declaration, I know this


    You do?

    > int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    > using std::vector???


    Yes.
    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Apr 8, 2011
    #3
  4. * Victor Bazarov, on 08.04.2011 23:41:
    > On 4/8/2011 5:31 PM, Stephen Howe wrote:
    >> Hi
    >>
    >> I cant find whether this is valid C++, but I believe it is
    >>
    >> // ---------------------------- start header file
    >> #include<vector>
    >>
    >> // Forward Declaration
    >> class FooBar;
    >>
    >> int SomeFunction1(FooBar); // Valid
    >> declaration, I know this
    >> int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    >> using std::vector???
    >>
    >> // ---------------------------- end header file
    >>
    >> Yes FooBar is incomplete but all I am interested in is whether it is a
    >> valid declaration.
    >> All of this is to minimise header file dependency, so FooBar's
    >> definition is not dragged in.
    >> I know that where SomeFunction2 is defined, a full definition of
    >> FooBar is needed.

    >
    > Since in the context of the declaration of 'SomeFunction2' the full definition
    > of 'std::vector<FooBar>' is not required, it is not going to be instantiated. If
    > no instantiation happens, FooBar may be incomplete. The declaration of
    > 'SomFunction2' is legal, I suppose.


    Not formally.

    C++98 §17.4.3.6/2, about standard library containers:
    "In particular, the effects are undefined in the following cases:
    [blah blah]
    - if an incomplete type (3.9) is used as a template argument when
    instantiating a template component"

    That is, standard libary containers are special, in that the element type must
    (formally) be complete.

    A compiler is free to check, by any means, that the type is complete.

    Doing such checking yourself might look like this:


    <code>
    namespace pedantic {

    template< class Elem, int enforcedCompleteness = sizeof( Elem ) >
    class Vector
    {
    // ...
    };
    }

    // Forward Declaration
    class FooBar;

    int SomeFunction1( FooBar ); // Valid.
    int SomeFunction2( pedantic::Vector<FooBar>& ref ); // Invalid.

    int main()
    {}
    </code>


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Apr 9, 2011
    #4
  5. Stephen Howe

    Pavel Guest

    Alf P. Steinbach /Usenet wrote:
    > * Victor Bazarov, on 08.04.2011 23:41:
    >> On 4/8/2011 5:31 PM, Stephen Howe wrote:
    >>> Hi
    >>>
    >>> I cant find whether this is valid C++, but I believe it is
    >>>
    >>> // ---------------------------- start header file
    >>> #include<vector>
    >>>
    >>> // Forward Declaration
    >>> class FooBar;
    >>>
    >>> int SomeFunction1(FooBar); // Valid
    >>> declaration, I know this
    >>> int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    >>> using std::vector???
    >>>
    >>> // ---------------------------- end header file
    >>>
    >>> Yes FooBar is incomplete but all I am interested in is whether it is a
    >>> valid declaration.
    >>> All of this is to minimise header file dependency, so FooBar's
    >>> definition is not dragged in.
    >>> I know that where SomeFunction2 is defined, a full definition of
    >>> FooBar is needed.

    >>
    >> Since in the context of the declaration of 'SomeFunction2' the full
    >> definition
    >> of 'std::vector<FooBar>' is not required, it is not going to be
    >> instantiated. If
    >> no instantiation happens, FooBar may be incomplete. The declaration of
    >> 'SomFunction2' is legal, I suppose.

    >
    > Not formally.
    >
    > C++98 §17.4.3.6/2, about standard library containers:
    > "In particular, the effects are undefined in the following cases:
    > [blah blah]
    > - if an incomplete type (3.9) is used as a template argument when
    > instantiating a template component"

    Why do you think the declaration in OP has to instantiate std::vector<FooBar>?

    From 14.7.1-1 (C++ 2003):
    Unless a class template specialization has been explicitly instantiated (14.7.2)
    or explicitly specialized
    (14.7.3), the class template specialization is implicitly instantiated when the
    specialization is referenced in a
    context that requires a completely-defined object type or when the completeness
    of the class type affects the
    semantics of the program.

    std::vector<FooBar>& does not seem to require a completely-defined object.

    -Pavel

    >
    > That is, standard libary containers are special, in that the element
    > type must (formally) be complete.
    >
    > A compiler is free to check, by any means, that the type is complete.
    >
    > Doing such checking yourself might look like this:
    >
    >
    > <code>
    > namespace pedantic {
    >
    > template< class Elem, int enforcedCompleteness = sizeof( Elem ) >
    > class Vector
    > {
    > // ...
    > };
    > }
    >
    > // Forward Declaration
    > class FooBar;
    >
    > int SomeFunction1( FooBar ); // Valid.
    > int SomeFunction2( pedantic::Vector<FooBar>& ref ); // Invalid.
    >
    > int main()
    > {}
    > </code>
    >
    >
    > Cheers & hth.,
    >
    > - Alf
    >
     
    Pavel, Apr 9, 2011
    #5
  6. * Pavel, on 09.04.2011 05:17:
    > Alf P. Steinbach /Usenet wrote:
    >> * Victor Bazarov, on 08.04.2011 23:41:
    >>> On 4/8/2011 5:31 PM, Stephen Howe wrote:
    >>>> Hi
    >>>>
    >>>> I cant find whether this is valid C++, but I believe it is
    >>>>
    >>>> // ---------------------------- start header file
    >>>> #include<vector>
    >>>>
    >>>> // Forward Declaration
    >>>> class FooBar;
    >>>>
    >>>> int SomeFunction1(FooBar); // Valid
    >>>> declaration, I know this
    >>>> int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
    >>>> using std::vector???
    >>>>
    >>>> // ---------------------------- end header file
    >>>>
    >>>> Yes FooBar is incomplete but all I am interested in is whether it is a
    >>>> valid declaration.
    >>>> All of this is to minimise header file dependency, so FooBar's
    >>>> definition is not dragged in.
    >>>> I know that where SomeFunction2 is defined, a full definition of
    >>>> FooBar is needed.
    >>>
    >>> Since in the context of the declaration of 'SomeFunction2' the full
    >>> definition
    >>> of 'std::vector<FooBar>' is not required, it is not going to be
    >>> instantiated. If
    >>> no instantiation happens, FooBar may be incomplete. The declaration of
    >>> 'SomFunction2' is legal, I suppose.

    >>
    >> Not formally.
    >>
    >> C++98 §17.4.3.6/2, about standard library containers:
    >> "In particular, the effects are undefined in the following cases:
    >> [blah blah]
    >> - if an incomplete type (3.9) is used as a template argument when
    >> instantiating a template component"
    >>
    >> That is, standard libary containers are special, in that the element
    >> type must (formally) be complete.
    >>
    >> A compiler is free to check, by any means, that the type is complete.
    >>
    >> Doing such checking yourself might look like this:
    >>
    >>
    >> <code>
    >> namespace pedantic {
    >>
    >> template< class Elem, int enforcedCompleteness = sizeof( Elem ) >
    >> class Vector
    >> {
    >> // ...
    >> };
    >> }
    >>
    >> // Forward Declaration
    >> class FooBar;
    >>
    >> int SomeFunction1( FooBar ); // Valid.
    >> int SomeFunction2( pedantic::Vector<FooBar>& ref ); // Invalid.
    >>
    >> int main()
    >> {}
    >> </code>


    > Why do you think the declaration in OP has to instantiate std::vector<FooBar>?
    >
    > From 14.7.1-1 (C++ 2003):
    > Unless a class template specialization has been explicitly instantiated (14.7.2)
    > or explicitly specialized
    > (14.7.3), the class template specialization is implicitly instantiated when the
    > specialization is referenced in a
    > context that requires a completely-defined object type or when the completeness
    > of the class type affects the
    > semantics of the program.
    >
    > std::vector<FooBar>& does not seem to require a completely-defined object.


    Uh, you're right, it's not instantiated here. Sorry for noize.


    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Apr 9, 2011
    #6
  7. Stephen Howe

    Stephen Howe Guest

    >      C++98 17.4.3.6/2, about standard library containers:
    >      "In particular, the effects are undefined in the following cases:
    >       [blah blah]
    >       - if an incomplete type (3.9) is used as a template argument when
    >         instantiating a template component"


    Yes but Alf I am only interested in legality of declaration, not
    definition (nor instantiation).
    I can assure you that at the point when I call the function, the full
    definition of FooBar will be available.

    I am trying to minimise the amount of header file inclusion by forward
    declaring items as much as possible.
    I know that it perfectly legal for non-template class/struct/union
    parameters (but interestingly enum is left out (any aficionado saying
    that size matters here is wrong, if it does not matter for class/
    struct/union, it should not matter for enum; enum has been
    overlooked)).
    I was just discussing the legality of template container parameters
    where the containing type is incomplete, and as others have concluded,
    it is legal.

    That just leaves std::string and similar where unfortunately you do
    have to do have to do #include <string>, you cannot forward declare.
    And I do know about header file <iosfwd> which is useful to know (wish
    other std::eek:bject types had a fwd header).

    Thanks

    Stephen Howe
     
    Stephen Howe, Apr 9, 2011
    #7
  8. Stephen Howe

    Stephen Howe Guest

    Pavel

    If I had

    int SomeFunction3(std::vector<FooBar> ref);

    in a declaration, I dont think this requires FooBar to be complete
    either.

    For a long time, I thought only references and pointer types can be
    incomplete.
    But I read Scott Meyers and he assured return-by-value and pass-by-
    value types can also be incomplete (as long as it just a declaration).
    This seems right.
    I went through another round of removing headers and replacing with
    forward declarations.

    I think the template containers with incomplete types have exactly the
    same semantics as struct/class/union parameters that are incomplete.

    This is great news - miminise header file dependency, increase
    compilation speed (less headers for the compiler to wade through). If
    I do "#include myheader.h", I really want to minimise the number of
    dependent headers that are sub-included.

    All that really matters is when you come to call the function or
    define it, you do have full set of definitions then.

    Thanks

    Stephen Howe
     
    Stephen Howe, Apr 9, 2011
    #8
  9. Stephen Howe

    Pavel Guest

    Stephen Howe wrote:
    > Pavel
    >
    > If I had
    >
    > int SomeFunction3(std::vector<FooBar> ref);
    >
    > in a declaration, I dont think this requires FooBar to be complete
    > either.
    >
    > For a long time, I thought only references and pointer types can be
    > incomplete.
    > But I read Scott Meyers and he assured return-by-value and pass-by-
    > value types can also be incomplete (as long as it just a declaration).
    > This seems right.
    > I went through another round of removing headers and replacing with
    > forward declarations.
    >
    > I think the template containers with incomplete types have exactly the
    > same semantics as struct/class/union parameters that are incomplete.
    >
    > This is great news - miminise header file dependency, increase
    > compilation speed (less headers for the compiler to wade through). If
    > I do "#include myheader.h", I really want to minimise the number of
    > dependent headers that are sub-included.
    >
    > All that really matters is when you come to call the function or
    > define it, you do have full set of definitions then.
    >
    > Thanks
    >
    > Stephen Howe
    >

    Thanks Stephen!

    This is a nice feature to slash some compilation time, especially for headers
    with fat APIs where complete types of many parameters are not needed till the
    end of the including translation unit. It's somewhat less of a saver for highly
    coherent APIs.

    -Pavel
     
    Pavel, Apr 10, 2011
    #9
    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. qazmlp
    Replies:
    1
    Views:
    615
    Jonathan Turkanis
    Feb 15, 2004
  2. Replies:
    5
    Views:
    353
    James Kanze
    Apr 27, 2007
  3. er
    Replies:
    1
    Views:
    402
    Barry
    Sep 5, 2007
  4. Replies:
    7
    Views:
    243
  5. Replies:
    2
    Views:
    482
Loading...

Share This Page