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 |