Copy Link
Add to Bookmark
Report

C++ Newsletter/Tutorial Issue 18

eZine's profile picture
Published in 
CPPNL
 · 7 Mar 2022

Issue #018
December, 1996

Contents

  • Notes From ANSI/ISO - Function Lookup in Namespaces
  • Notes From ANSI/ISO - State of the C++ Standard
  • Introduction to Exception Handling Part 4 - Handling an Exception
  • Using C++ as a Better C Part 18 - Hiding Names
  • Introduction to STL Part 5 - Bit Sets

NOTES FROM ANSI/ISO - FUNCTION LOOKUP IN NAMESPACES

Jonathan Schilling, jls@sco.com

An important change has recently been made in the way functions are found within namespaces.

The three basic ways of making the contents of a namespace visible were discussed in C++ Newsletters #002 and #004. These are: explicit qualification, using directives, and using declarations.

Consider the following namespace, which declares a class and some (non-member) functions:

    namespace N { 
class A { ... };
A& operator+(const A&, const A&);
void f(A);
void g();
}


Now consider the following function that takes arguments of the class type:

    void z(N::A x, N::A y) 
{
x + y; // (1)
f(x); // (2)
g(); // (3)
}


Given the original rules for namespaces (just the three basic methods of namespace visibility), all three of the statements in this function are compilation errors, because none of the functions being called are visible.

However the standards committee has changed the way functions are looked up. Now there is a new language rule, which says that the namespaces of the classes of the arguments, and the namespaces of the base classes of those classes, are included in the search for function declarations, even when the contents of those namespaces are not otherwise visible.

So, when looking for an operator+() in (1) above, the arguments are x and y, the class of those arguments is A, and A is declared in namespace N. Thus the compiler looks for an operator+() in N, and finds one, and the call is legal. A similar process happens for the call to f() in (2).

However, the call to g() in (3) is still a compilation error, because there are no arguments to direct the lookup. The call would have to be made using one of the basic methods:

            N::g();         // explicit qualification


If the arguments to the function have different types, then all the associated namespaces are searched. Arguments of built-in types such as int have no associated namespace, while arguments of more complicated types such as pointers to functions bring in the namespaces of the pointed-to function's parameters and return type.

This new lookup rule was first added to solve some technical language definition problems with operator functions. It was then added to solve some other problems with template "dependent name" lookup (see C++ Newsletter #017) and template friends. At that point it was felt that consistency demanded the new rule be extended to lookup of all functions in all contexts, and this was done (albeit with some dissent within the committee) at the Stockholm meeting in July.

Because of the staggered introduction of this rule, for a while you may encounter compilers that implement it for operator functions but not for other functions, but eventually all implementations will be in full conformance.

One important thing to note about this rule change is that it is a step toward making namespaces a powerful scoping and packaging construct, rather than just a transparent vehicle to avoid name collisions. The art of employing namespaces is still in its early stages, and first reports have indicated that the basic methods of making names visible are sometimes too verbose (explicit qualification), too broad (using directives), or too prone to error and omission (using declarations). The new rule may help alleviate some of these problems.


NOTES FROM ANSI/ISO - STATE OF THE C++ STANDARD

Jonathan Schilling, jls@sco.com

At the meeting of the committee just concluded in November, a second "Committee Draft" (CD) was issued. This means a period of public review of the standard, and balloting on the standard, will now begin. This process is conducted by each of the national standards bodies involved (ANSI, the British Standards Institute, etc.).

The expectation is that this CD will be approved, with some modest corrections and changes required. A "Draft International Standard" would then be issued in late 1997. Despite its name, this will essentially be the final standard (modulo corrections for typos). It will then be subject to formal ballot and approval during 1998.

When the first CD was issued in April 1995, the draft standard was made publicly available on the Internet. However, it appears that due to ISO policy changes, this will not happen for this CD, and that non-committee members will have to pay their standards bodies for copies of the current draft standard if they are interested in reviewing it. Official details on all this should be appearing in the near future on the Usenet newsgroup comp.std.c++.


INTRODUCTION TO EXCEPTION HANDING PART 4 - HANDLING AN EXCEPTION

In previous issues we discussed throwing of exceptions and stack unwinding. Let's now look at actual handling of an exception that has been thrown. An exception is handled via an exception handler. For example:

    catch (T x) { 
// stuff
}


handles exceptions of type T. More precisely, a handler of the form:

    catch (T x) { 
// stuff
}


or:

    catch (const T x) { 
// stuff
}


or:

    catch (T& x) { 
// stuff
}


or:

    catch (const T& x) { 
// stuff
}


will catch a thrown exception of type E, given that:

  • T and E are the same type, or
  • T is an unambiguous public base class of E, or
  • T is a pointer type and E is a pointer type that can be converted to T by a standard pointer conversion

As an example of these rules, in the following case the thrown exception will be caught:

    #include <iostream.h> 

class A {};

class B : public A {};

void f()
{
throw B();
}

int main()
{
try {
f();
}
catch (const A& x) {
cout << "exception caught" << endl;
}

return 0;
}


because A is a public base class of B. Handlers are tried in order of appearance. If, for example, you place a handler for a derived class after a handler for a corresponding base class, it will never be invoked. If we had a handler for B after A, in the example above, it would not be called.

A handler like:

    catch (...) { 
// stuff
}


appearing as the last handler in a series, will match any exception type.

If no handler is found, the search for a matching handler continues in a dynamically surrounding try block. If no handler is found at all, a special library function terminate() is called, typically ending the program.

An exception is considered caught by a handler when the parameters to the handler have been initialized, and considered finished when the handler exits.

In the next issue we'll talk a bit about exception specifications, that are used to specify what exception types a function may throw.


USING C++ AS A BETTER C PART 18 - HIDING NAMES

Consider this small example:

    #include <stdio.h> 

int xxx[10];

int main()
{
struct xxx {
int a;
};

printf("%d\n", sizeof(xxx));

return 0;
}


When compiled as C code, it will typically print a value like 20 or 40, whereas when treated as C++, the output value will likely be 2 or 4.

Why is this? In C++, the introduction of the local struct declaration hides the global "xxx", and the program is simply taking the size of a struct which has a single integer member in it. In C, "sizeof(xxx)" refers to the global array, and a tag like "xxx" doesn't automatically refer to a struct.

If we said "sizeof(struct xxx)" then we would be able to refer to the local struct declaration.


INTRODUCTION TO STL PART 5 - BIT SETS

We've been looking at various types of data structures found in the Standard Template Library. Another one of these is bit sets, offering space-efficient support for sets of bits. Let's look at an example:

    #include <iostream> 
#include <bitset>

using namespace std;

int main()
{
bitset<16> b1("1011011110001011");
bitset<16> b2;

b2 = ~b1;

for (int i = b2.size() - 1; i >= 0; i--)
cout << b2[i];
cout << endl;

return 0;
}


A declaration like:

    bitset<16> b1("1011011110001011");


declares a 16-long set of bits, and initializes the value of the set to the specified bits.

We then operate on the bit set, in this example performing a bitwise NOT operation, that is, toggling all the bits. The result of this operation is stored in b2.

Finally, we iterate over b2 and display all the bits. b2.size() returns the number of bits in the set, and the [] operator is overloaded to provide access to individual bits.

There are other operations possible on bit sets, for example the flip() function to toggle an individual bit.


ACKNOWLEDGEMENTS

Thanks to Nathan Myers, Eric Nagler, David Nelson, Terry Rudd, Jonathan Schilling, Elaine Siegel, and Clay Wilson for help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com with this line as its message body:

subscribe c_plus_plus

Back issues are available via FTP from:

rmi.net /pub2/glenm/newslett

or on the Web at:

http://rainbow.rmi.net/~glenm

There is also a Java newsletter. To subscribe to it, say:

subscribe java_letter

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1996 Glen McCluskey. All Rights Reserved.

This newsletter may be further distributed provided that it is copied in its entirety, including the newsletter number at the top and the copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional C++ Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmi.net /pub2/glenm/newslett (for back issues)
Web: http://rainbow.rmi.net/~glenm

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT