Topic: Implementing new-style headers


Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/27
Raw View
Tanveer Gani <tanveerg@microware.com> wrote:
>> The only other issue regarding the new-style headers that I'm aware
>> of is that the "optional" macros in the C library can only be defined
>> as inline functions in the new style headers. For example, having a
>> macro for fgetc() is prohibited. Is there any other issue I need to
>> be aware of?

Nathan Myers wrote:
> Plenty.  Koenig lookup means that any types specified as defined
> in namespace std really have to be defined there; typedefs aren't
> sufficient.  In other words,
>
>   #include <ctime>
>   std::tm tmbuf;
>   std::time_t t = mktime(&tmbuf);  // no std:: required
>
> is legal, because using a type defined in std (tm) means that
> names of functions called using that type are looked up in std.

Does this apply to user-defined functions taking parms of type
std::tm as well?

    #include <ctime>

    int myFunc(std::tm *t) { ... }        // In unnamed namespace

    namespace Mine
    {
    int myOtherFunc(std::tm *t) { ... }   // In Mine:: namespace
    }

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/07/28
Raw View
David R Tribble <dtribble@technologist.com> wrote:
>Nathan Myers wrote:
>>
>>   #include <ctime>
>>   std::tm tmbuf;
>>   std::time_t t = mktime(&tmbuf);  // no std:: required
>>
>> is legal, because using a type defined in std (in this case, tm)
>> means that names of functions called using that type are looked
>> up in std.
>
>Does this apply to user-defined functions taking parms of type
>std::tm as well?
>
>    #include <ctime>
>    int myFunc(std::tm *t) { ... }        // In unnamed namespace
>    namespace Mine {
>      int myOtherFunc(std::tm *t) { ... }   // In Mine:: namespace
>    }

I'm not sure I understand the example.  Maybe I can answer the
question anyway:

  namespace Mine  // reopening it to add...
  {
    struct Mytm {};
    int myOtherFunc(Mytm *t) { ... }
  }

  int main()
  {
    tm tmbuf;
    myFunc(&tmbuf);       // OK
    myOtherFunc(&tmbuf);  // error, myOtherFunc not in :: or std::

    Mine::Mytm mytmbuf;
    myOtherFunc(&mytmbuf);  // OK, found.
  }

Incidentally, Koenig lookup has some other interesting effects.
For instance,

  #include <ctime>
  namespace Mine {
    std::time_t mktime(std::tm*);  // My own Mine::mktime.
  }
  int main()
  {
    std::tm tmbuf;
    using Mine::mktime;
    mktime(&tmbuf);   // ambiguous!
  }

This happens because Koenig lookup is always "on", and
adds to the overload set obtained by normal scoped lookup.
Koenig lookup finds std::mktime, and normal scoped lookup
finds Mine::mktime, with no reason to prefer one over the
other.  More confusing might be if the std:: function is
a *better* match than the locally-declared one; then it
will choose the other, silently:

  struct A {};
  struct B : A {};
  void f(B&);

  namespace X { void f(A&); }

  int main()
  {
    B b;
    using X::f;
    f(b);      // gets ::f, not X::f
  }

It might seem surprising to find that despite that you
"asked for" X::f, you got ::f.  Here, since B is defined
in the global namespace, lookup always happens there when
you use a B in addition to the local scope, so the overload
set here is (::f, B::f), and ::f is a better match.

The lesson is: avoid defining types (or anything else, for that
matter) in the global namespace.  And qualify non-local names.
But we knew that already, didn't we?

Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.org/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Tanveer Gani <tanveerg@microware.com>
Date: 1998/07/21
Raw View
Hi all,

I'm faced with the task of implementing the new style headers and I
want to get them right the first time.

Going through the FDIS (Nov 97), I see that section D.5 [depr.c.headers]

contains the following in para 2:

        "Each C header whose name has the form name.h, behaves as if
        each name placed in the Standard library namespace by the
        corresponding cname header is also placed within the namespace
        scope of the namespace std and is followed by an explicit
        using-declaration (7.3.3)"

This I have interpreted as meaning that a <cxyz> header will have all
declarations for the corresponding <xyz.h> C header in namespace std;
further, the <xyz.h> header can be implemented (minimally) as:

        // xyz.h
        #include <cxyz>
        using namespace std;

Then, my first question is: Is the following a legal C++ program?

        #include <iostream>
        #include <stdio.h>

        int main()
        {
                cout << "hello" << endl;  // no std:: qualification
        }

If it isn't then the aforementioned implementation can't be
used. Rather, <xyz.h> would have to redeclare all functions in <cxyz>
in the global namespace in lieu of the using-declaration.

 I've also seen two other implementations of <cxyz> headers; the first
one goes like:

        // <cstdio>

        #include <stdio.h>

        namespace std {
                using ::printf;
                using ::scanf;
                // etc.
        }

I believe this implementation does not conform to the Standard, since
the following is an ill-defined program which may not (should not?)
compile:

        #include <cstdio>
        int main() { printf(""); } // should be std::printf

The other technique I've come across is to implement <cxyz> as

        namespace std {
                #include <xyz.h>
        }

The problem with this is that implementations of C standard headers
usually contain multiple inclusion guards. Thus, the following will
cause a program using the above implementation technique fail to
compile:

        #include <stdio.h>  // may also be included from some other
header
        #include <cstdio>   // declares an empty namespace due to
                            // guard in <stdio.h>

        int main() { std::printf(""); }  // error! std:: has no member
printf


The only other issue regarding the new-style headers that I'm aware of
is that the "optional" macros in the C library can only be defined as
inline functions in the new style headers. For example, having a macro
for fgetc() is prohibited. Is there any other issue I need to be aware
of?

Any input on this issue would be much appreciated.


Regards,

Tanveer Gani,
Compiler Group
Microware Systems Corp.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1998/07/21
Raw View
In article <35B37F11.E748998D@microware.com>,
Tanveer Gani  <tanveerg@microware.com> wrote:

> This I have interpreted as meaning that a <cxyz> header will have all
> declarations for the corresponding <xyz.h> C header in namespace std;
> further, the <xyz.h> header can be implemented (minimally) as:

>         // xyz.h
>         #include <cxyz>
>         using namespace std;

Not quite, because "using namespace std" puts all names into the
global namespace, but the standard says that only the names that
are required to be defined in <cxyz> should go into the global namespace.

> Then, my first question is: Is the following a legal C++ program?

>         #include <iostream>
>         #include <stdio.h>

>         int main()
>         {
>                 cout << "hello" << endl;  // no std:: qualification
>         }

No, because cout isn't one of the names in stdio.h

> If it isn't then the aforementioned implementation can't be
> used. Rather, <xyz.h> would have to redeclare all functions in <cxyz>
> in the global namespace in lieu of the using-declaration.

No, xyz.h has to use using-declarations rather than using-directives.

--
    --Andrew Koenig
      ark@research.att.com
      http://www.research.att.com/info/ark



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/07/21
Raw View
Tanveer Gani <tanveerg@microware.com> wrote:
>contains the following in para 2:
>
>        "Each C header whose name has the form name.h, behaves as if
>        each name placed in the Standard library namespace by the
>        corresponding cname header is also placed within the namespace
>        scope of the namespace std and is followed by an explicit
>        using-declaration (7.3.3)"
>
>This I have interpreted as meaning that a <cxyz> header will have all
>declarations for the corresponding <xyz.h> C header in namespace std;
>further, the <xyz.h> header can be implemented (minimally) as:
>
>        // xyz.h
>        #include <cxyz>
>        using namespace std;

No, this is not sufficient.

>Then, my first question is: Is the following a legal C++ program?
>
>        #include <iostream>
>        #include <stdio.h>
>
>        int main()
>        {
>                cout << "hello" << endl;  // no std:: qualification
>        }

No.

>If it isn't then the aforementioned implementation can't be
>used. Rather, <xyz.h> would have to redeclare all functions in <cxyz>
>in the global namespace in lieu of the using-declaration.

That wouldn't work either.

> I've also seen two other implementations of <cxyz> headers; the first
>one goes like:
>
>        // <cstdio>
>
>        #include <stdio.h>
>
>        namespace std {
>                using ::printf;
>                using ::scanf;
>                // etc.
>        }
>
>I believe this implementation does not conform to the Standard, since
>the following is an ill-defined program which may not (should not?)
>compile:
>
>        #include <cstdio>
>        int main() { printf(""); } // should be std::printf

Right: "a diagnostic is required".

>The other technique I've come across is to implement <cxyz> as
>
>        namespace std {
>                #include <xyz.h>
>        }
>
>The problem with this is that implementations of C standard headers
>usually contain multiple inclusion guards.

That's only the half of it!  What about other files included by xyz.h?

>The only other issue regarding the new-style headers that I'm aware of
>is that the "optional" macros in the C library can only be defined as
>inline functions in the new style headers. For example, having a macro
>for fgetc() is prohibited. Is there any other issue I need to be aware
>of?

Plenty.  Koenig lookup means that any types specified as defined
in namespace std really have to be defined there; typedefs aren't
sufficient.  In other words,

  #include <ctime>
  std::tm tmbuf;
  std::time_t t = mktime(&tmbuf);  // no std:: required

is legal, because using a type defined in std (tm) means that
names of functions called using that type are looked up in std.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.org/



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]