[comp.lang.c++] nit-picking - Edition #3

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (05/11/89)

Well friends... it's that time again.  I've built up another store of
language nits to pick at and I would like to get some more answers.

I know that a lot of these nits that I have been picking at are in the
dark little corners of the language where most people never venture,
but I believe that these questions (and more importantly, the answers)
will help to insure that those few brave souls who do go into these
places will not be forever lost in a twisty maze of little language
features (all different).

I should clarify that (once again) I am looking for responses from
qualified language lawyers regarding the state of affairs which will
exist once cfront 2.0 bursts upon the scene.

In my previous two installments of nit-picking questions, both Bjarne
and Andrew K. have very generously given their time to respond to my
nits.  I do appreciate it.  I hope that everyone else who reads this
newsgroup also appreciates it because I know that Bjarne and Andrew
are very busy guys right about now.  After all, there is a new release
to get shipped and a new Reference Manual to get finished!  Either
one, all by itself, constitutes a good bit of work indeed!

Anyway, the point is that I hope that I'm not stretching their patience
too much by posting this third edition of nits at this very busy time.
I (and some others who have sent E-mail to me) are just getting too
much enlightenment for me to pause right now and wait for the software
to get out and catch up to my curiousity.

So here goes...

----------------------------------------------------------------------
Is it legal to declare an operator such that one or more
of its formal arguments have default values?  If this is
allowed, and if one of the operators which can be either
unary or binary (i.e. +, -, *, &) is declared globally
(i.e. outside of any class/struct/union declarations)
as a binary operator with exactly one default formal argument
value, then is this operator invoked for those cases in
which the given operator is used as a unary operator?

Is it legal to declare a unary operator with more than one
formal argument (or more than zero formal arguments if the
operator is a class member).

Is it legal to declare a binary operator with either more that
two or less than two formal arguments (or more than one or
less than one formal arguments if the operator is a class
member).

Is it legal to explicitly declare the return type of a type
conversion operator?  If so, is it legal to explicitly
declare the return type of a type conversion operator to be
some type other than the type whose name is the name of the
conversion operator itself?  For example:

	type1 operator type2 (type3 x);

If the declaration above is legal, then is it legal for the return
type of an operator to be type "void"?

Is it legal to declare an operator to return a type "void"?  In
particular, is it legal to declare a type conversion operator which
converts objects of a given type to objects of type "void"?

When you take the address of a function which is itself a member
of a given class, and you do it within some member function of
the same class, are you required to explicitly qualify the entity
with "class_name::" or is that implicitly provided by the compiler?
For example:

	struct base {
		typedef void (base::*PMB) ();

		void member_1 () {}
		void member_2 ()
		{
			PMB pmb = &member_1;	// legal ?
		}
	};

Is it legal to take the address of a (data) member of a class?  For example,
consider the various cases shown below:

	struct base {
		int data_member;
		void function_member ()
		{
			void* p0 = &this->data_member;	// legal ?
			void* p1 = &data_member;	// legal ?
			void* p2 = &base::data_member;	// legal ?
		}
	};

If the uses of the address-of operator shown above are legal, what do
they yield?

If you take the address of a member function or operator, and the name of
that member function (or operator designator), when taken alone, is sufficient
to fully disambiguate your reference (such as when there are *no* other
overloadings of the given function name or operator designator defined
for the given (context) function),  is the reference legal even though
it would have been considered ambiguous (and therefore illegal) if there
*had* in fact been overloadings?  For example:

	struct base {
		void not_overloaded ();
		int operator ! ();
	};

	int test ()
	{
		void* p1 = &base::not_overloaded;	// legal ?
		void* p2 = &base::operator!;		// legal ?
	}

Is it legal to define operator[] outside of a class declaration?
If so, what effect does this have?

Is it legal to define operator() outside of a class declaration?
If so, what effect does this have?

Is it legal to define operator-> outside of a class declaration?
If so, what effect does this have?

Is operator[] classified as a binary operator?  Can operator[]
accept either more or less than two arguments?

Is operator() classified as a unary operator? Can operator()
accept either more or less that one argument?

Is operator-> classified as a unary operator? Can operator->
accept either more or less that one argument?

Why are type conversion operators only allowed as members?

According to the original Reference Manual, it is legal for a switch
statement to contain cases which are positioned so as to circumvent
the (sensible) restriction placed on goto's that control cannot be
transfered past a point at which a class "auto" object would be
constructed.  Are the rules regarding such disgustingly unstructured
switch-initiated transfers going to be tightened up so that pathological
cases (like the following) will be strictly prohibited?

	struct base {
		base (int i);
		~base ();
	};
	
	void main ()
	{
		switch (1) {
		case 0:
			{
			    base base_object (1);
		case 1:				// entering the twlight zone...
			break;
			}		// is base_object destructed here ????
		}
	}

Are there any such things as "implicitly" declared X::X(X&) constructors for
builtin types?  Specifically, is the following legal:

	struct base {
		int data_member;

		base (int i) : data_member (i)		// legal?
		{
		}
	};

May a static member function be (a) virtual, or (b) inline?

When allocating space for vectors of objects, are (or can)
constructors be called for each (object) member of the vector?
Specifically, is the following code legal?

	class base {
		int member1;
		int member2;
	public:
		base (int i, int j);
		base ();
	};
	
	base* bp;
	
	int main ()
	{
		bp = new base[20];
		bp = new base (7,8)[20];	// legal ???
	}

Is it legal to obtain the address of a member function "dynamically"
through a dereferenced and qualified pointer to an object?  Specifically,
which (if any) of the following examples are legal?

	class C {
	public:
		void f1 (int, int);
		virtual void f2 (int, int);
	};

	typedef void (C::*C_member_func_ptr) (int, int);

	C* Cp;
	C_member_func_ptr p;

	void test ()
	{
		p = Cp->f1;		// legal ?
		p = Cp->f2;		// legal ?
		p = (*Cp).f1;		// legal ?
		p = (*Cp).f2;		// legal ?

		p = & Cp->f1;		// legal ?
		p = & Cp->f2;		// legal ?
		p = & (*Cp).f1;		// legal ?
		p = & (*Cp).f2;		// legal ?
	}

Does the second declaration statement below declare two references,
or one reference to an object of type T and one actual object of type T?

	T T_object;

	T & one = T_object, two = T_object;

Is it legal to create references to functions?  To operators?  To
member functions?  For example:


	struct S {
		int member (S s2);
	};

	typedef int (func_ref&) (S s1, S s2);		// legal ?
	typedef int (S::&S_member_ref) (S s2);		// legal ?

	int global_func (S s1, S s2) { return 0; }
	int operator% (S s1, S s2) { return 0; }

	func_ref fr1 = global_func;			// legal ?
	func_ref fr2 = & global_func;			// legal ?

	func_ref fr3 = operator%;			// legal ?
	func_ref fr4 = & operator%;			// legal ?

	S_member_ref smr_1 = S::member;			// legal ?
	S_member_ref smr_2 = & S::member;		// legal ?

-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

mball@cod.NOSC.MIL (Michael S. Ball) (05/11/89)

I can't possibly be as authoritative as Bjarne or Andy, but I'll give
it a go.  Things may have changed recently, but probably not too much.
I've had to cut down the quotes to make it past the stupid mailer.
I hope there is enough context left for you to understand the answers.

In article <203@riunite.ACA.MCC.COM> rfg@riunite.UUCP (Ron Guilmette) writes:
>Is it legal to declare an operator such that one or more
>of its formal arguments have default values?  If this is
>allowed,

yes, it is

>	and if one of the operators which can be either
>unary or binary (i.e. +, -, *, &) is declared globally
>(i.e. outside of any class/struct/union declarations)
>as a binary operator with exactly one default formal argument
>value, then is this operator invoked for those cases in
>which the given operator is used as a unary operator?

Yes again.  You should realize, however, that for a unary
operator to be eligible for overloading it must be of a class
type, which means that the non-defaulted argument must be of
a class type.

>Is it legal to declare a unary operator with more than one
>formal argument (or more than zero formal arguments if the
>operator is a class member).

No, by definition of unary.

>Is it legal to declare a binary operator with either more that
>two or less than two formal arguments (or more than one or
>less than one formal arguments if the operator is a class
>member).

No, unless you count the () operator, which is hard to consider
as a true binary.  The argument list is considered to be one
argument

>Is it legal to explicitly declare the return type of a type
>conversion operator?

No.
The rest of the discussion is moot, since it is illegal to declare
a return type at all.

>Is it legal to declare an operator to return a type "void"?  In
>particular, is it legal to declare a type conversion operator which
>converts objects of a given type to objects of type "void"?

I don't see why not, but it would be a bit hard to apply except
explicity.  I'm not sure why this would be useful.

>When you take the address of a function which is itself a member
>of a given class, and you do it within some member function of
>the same class, are you required to explicitly qualify the entity
>with "class_name::" or is that implicitly provided by the compiler?

It must be explicitly qualified, though some older versions of the
language had different rules.

>Is it legal to take the address of a (data) member of a class?  For example,

Yes.

>consider the various cases shown below:
:
>			void* p0 = &this->data_member;	// legal ?

This is legal, and returns a pointer to the particular member in the
particular instance with which the function was invoked

>			void* p1 = &data_member;	// legal ?

The same as the previous example.

>			void* p2 = &base::data_member;	// legal ?

Taking the address is legal, but assigning to void* is not.  It may be
cast to an integral type, in which case the value will be the offset of
the member within the class.  It may only be dereferenced using .* or
->* operators.

>If the uses of the address-of operator shown above are legal, what do
>they yield?
>		void* p1 = &base::not_overloaded;	// legal ?
>		void* p2 = &base::operator!;		// legal ?

In both cases taking the address is legal, but the assignment is not.
There is no ambiguity here.

>Is it legal to define operator[] outside of a class declaration?

Yes

>If so, what effect does this have?

It's a binary operator which does whatever you write it to do.

>Is it legal to define operator() outside of a class declaration?

No

>If so, what effect does this have?

A compile-time error

>Is it legal to define operator-> outside of a class declaration?

No

>Is operator[] classified as a binary operator?  Can operator[]

Yes.

>accept either more or less than two arguments?

No

>Is operator() classified as a unary operator? Can operator()

No, binary, the right hand operand is the entire argument list,
so it is legal to write 
  class c;
    c cv;
    cv(arg1, arg2, arg3);
which is equivalent to
    cv.operator()(arg1, arg2, arg3);

>Is operator-> classified as a unary operator? Can operator->

Yes, it is a unary postfix operator which must return either a
pointer or another class with operator -> defined.  When it returns
a pointer the dereference and selection is applied to that
pointer.

>Why are type conversion operators only allowed as members?

I don't know, since I haven't tried to implement a compiler
which doesn't have this restriction.  It seems reasonable to me.

>	  Are the rules regarding such disgustingly unstructured
>switch-initiated transfers going to be tightened up so that pathological
>cases (like the following) will be strictly prohibited?

They are, it is illegal for the flow of control to bypass an initialization
without bypassing the entire block.

> Disgusting example deleted...

>Are there any such things as "implicitly" declared X::X(X&) constructors for
>builtin types?  Specifically, is the following legal:

>		base (int i) : data_member (i)		// legal?
This is legal.

>May a static member function be (a) virtual, or (b) inline?

Since a static member function is invoked without an object, I don't
see how it could be virtual.  It could certainly be inline.

>When allocating space for vectors of objects, are (or can)
>constructors be called for each (object) member of the vector?
:
>		bp = new base[20];
>		bp = new base (7,8)[20];	// legal ???

Only the default constructor can be used to initialize an array, so the
first example is legal, and each element will get the default constructor.
the second example is illegal.

>Is it legal to obtain the address of a member function "dynamically"
>through a dereferenced and qualified pointer to an object?

No, you must use &c::func, though some older compilers allow it.

>Does the second declaration statement below declare two references,
>or one reference to an object of type T and one actual object of type T?
:
>	T & one = T_object, two = T_object;

One reference, just as in C pointer types.

>Is it legal to create references to functions?

I don't see how, since you can't initialize it.  Since pointers to 
functions are automatically dereferenced anyway, it seems moot.

>		To operators?

what does this mean?  It's a reference to a type.

>member functions?  For example:

No

>	typedef int (func_ref&) (S s1, S s2);		// legal ?

probably, but useless.

>	typedef int (S::&S_member_ref) (S s2);		// legal ?

no.

>	func_ref fr1 = global_func;			// legal ?

I would think not, since global_func is a function pointer, not a function.

>	func_ref fr2 = & global_func;			// legal ?

Definitely illegal.

>	func_ref fr3 = operator%;			// legal ?
>	func_ref fr4 = & operator%;			// legal ?

exactly the same as above

>	S_member_ref smr_1 = S::member;			// legal ?
>	S_member_ref smr_2 = & S::member;		// legal ?
illegal

Mike Ball
TauMetric Corporation
1094 Cudahy Place, Ste 302
San Diego, CA 92110
(619)275-6381

schmidt@siam.ics.uci.edu (Doug Schmidt) (05/12/89)

Here's a quick nit.  Is the following a legal use of multiple
inheritance?  As you can see, from one direction class a's member
function `int foo ()' is private for all classes derived from class b.
However, on another path it is public.  In class d's constructor,
where `foo ()' is called, foo appears to be derived from classes where
it is both private and public.

Which visibility status prevails?  Is this ambiguous, legal, or illegal?

thanks,

        Doug

----------------------------------------
class a
{
public:
  int foo () { printf ("foo\n"); }
  a () {printf ("a\n");}
};

class b : public a
{
private:
  a::foo; // made private for all classes derived from class b.
public:
  b () {printf ("b\n");}
};

class c : public a
{
public:
  c () {printf ("c\n");}
};

class d : public c, public b
{
public:
  d () 
    {
      printf ("d\n"); 
      foo (); // both public *and* private!! which prevails?
    }
 };

class e : public d
{
public:
  e () 
    {
      printf ("e\n"); 
    } 
}

main ()
{
  e eek;
  b *beek = &eek;
}

--
On a clear day, under blue skies, there is no need to seek.
And asking about Buddha                +------------------------+
Is like proclaiming innocence,         | schmidt@ics.uci.edu    |
With loot in your pocket.              | office: (714) 856-4043 |