🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #4005

Re: Array function params and const qualifier

#4005
From: Fergus Henderson
Date: Fri, 12 Apr 1996 15:30
160 lines
7977 bytes
clamage@Eng.Sun.COM (Steve Clamage) writes:

>Adel El-Beik <A.El-Beik@man0506.wins.icl.co.uk> writes:
>>I have a question concerning MSVC++ v.4.00 and the April DWP C++.
>>
>>The following code fails on MSVC++.  It doesn't like line labelled 1.
>>It complains with 
>>
>>C:\array\array.cpp(16) : error C2664: 'func' : cannot convert parameter 1 
>>from 'long [2][2]' to 'const long [][2]' (new behavior; please see help)
>
>You have run into effectively the same rule that prohibits implicit
>conversion from "T**" to "const T**". That prohibition is not new,
>but is in the ISO/ANSI C standard, and has not been changed, since
>it would open a hole in the type system.

I suspect you are mistaken.  I believe Adel El-Beik has run into a bug
in MSVC++, rather than any prohibition in the draft C++ standard.
By my reading of the January 96 draft, I believe Adel El-Beik's code is
well-formed (i.e. legal).

[moderator's note: I agree I was wrong. Sorry for the confusion. -sdc ]

>I believe the subject is covered in the comp.lang.c FAQ list.

The comp.lang.c FAQ list may cover the case of conversion from `T**' to
`const T**' (although I couldn't find it in my old copy), but I'm sure
it does not cover the case of conversion from `T[n][m]' to `const
T(*)[m]', which I think is quite safe, and which is, I believe,
permitted by the draft C++ standard.

Here's the code again, and an explanation of why I believe the code is legal.

	typedef long bar[2][2];
	void func( const bar param ){}

	int main()
	{
		bar x;
		func(x);		// rejected by 
	}

The parameter of `func' is declared to have type `const bar', where
`bar' is a typedef which names an array type.  Consulting 3.9.3/3,

|   3.9.3  CV-qualifiers                            [basic.type.qualifier]
| 
| 2 A  compound  type  (_basic.compound_)  is  not cv-qualified by the cv-
|   qualifiers (if any) of the type from which it is compounded.  Any  cv-
|   qualifiers that appear in an array declaration apply to the array ele-
|   ment type, not the array type (_dcl.array_).

I think we can discern that the declared type of the
parameter is "array [2] of array [2] of const long", rather than
"const array [2] of array [2] of long".  The wording is quite vague [*]
but I'm pretty sure that's the intent.  However, this is certainly
the weakest step in my chain of reasoning.

	[*] What exactly is an "array declaration"?  Does `const bar'
	    count as one?  Does this rule apply recursively to arrays
	    of arrays?

Next, we need to consult 8.3.5/3.

|   8.3.5  Functions                                             [dcl.fct]
| 
| 3 [...] The type of a function is determined using the follow-
|   ing rules.  The type of each parameter  is  determined  from  its  own
|   decl-specifier-seq and declarator.  After determining the type of each
|   parameter, any parameter of type "array of T" or  "function  returning
|   T"  is adjusted to be "pointer to T" or "pointer to function returning
|   T," respectively. [...]

In this case, the type of the parameter is adjusted from "array [2] of
array [2] of const long" to "pointer to array [2] of const long".

So, we are trying to convert a value of type "array [2] of array [2] of long"
to type "pointer to array [2] of const long".  According to 4/1,

|   4   Standard conversions                              [conv]
| 
| 1 Standard conversions are implicit  conversions  defined  for  built-in
|   types.  The full set of such conversions is enumerated in this clause.
|   A standard conversion sequence is a sequence of  standard  conversions
|   in the following order:
| 
|   --Zero or one conversion from the following set: lvalue-to-rvalue con-
|     version, array-to-pointer conversion, and  function-to-pointer  con-
|     version.
| 
|   --Zero  or one conversion from the following set: integral promotions,
|     floating point promotion, integral conversions, floating point  con-
|     versions,   floating-integral   conversions,   pointer  conversions,
|     pointer to member conversions, base class conversions,  and  boolean
|     conversions.
| 
|   --Zero or one qualification conversion.

The first conversion we apply, then, is an array-to-pointer conversion.
Consulting 4.2/1,

|   4.2  Array-to-pointer conversion                          [conv.array]
| 
| 1 An  lvalue or rvalue of type "array of N T" or "array of unknown bound
|   of T" can be converted to an rvalue  of  type  "pointer  to  T."   The
|   result is a pointer to the first element of the array.

we see that we can convert our value of type "array [2] of array[2] of long"
to "pointer to array [2] of long".

We don't need to apply any conversions from the second set, but we
do need to apply a qualification conversion before we can get to
"pointer to array [2] of const long".  At first glance, 4.4/1

|   4.4  Qualification conversions                             [conv.qual]
| 
| 1 An  rvalue of type "pointer to cv1 T" can be converted to an rvalue of
|   type "pointer to cv2 T" if "cv2 T" is more cv-qualified than  "cv1 T."

does not seem to be of any help, since the "const" is on the wrong
side of the "array of".  However, this must be read in the context
of 3.9.3/5.

|   3.9.3  CV-qualifiers                            [basic.type.qualifier]
| 
| 5 In this International Standard, the notation cv (or cv1,  cv2,  etc.),
|   used  in  the description of types, represents an arbitrary set of cv-
|   qualifiers, i.e., one of {const}, {volatile},  {const,  volatile},  or
|   the  empty  set.  Cv-qualifiers applied to an array type attach to the
|   underlying element type, so the notation "cv T," where T is  an  array
|   type,  refers to an array whose elements are so-qualified.  Such array
|   types can be said to be more (or less) cv-qualified than  other  types
|   based on the cv-qualification of the underlying element types.

In our case, T is indeed an array type.  Reading 4.4/1 with `cv T'
everywhere replaced with `array of cv T', as is required by 3.9.3,
gives us the following rule:

||  An  rvalue of type "pointer to array of cv1 T" can be converted to an
||  rvalue of type "pointer to array of cv2 T" if "cv2 T" is more
||  cv-qualified than  "cv1 T."

Applying this rule to the case in question, we can convert to "pointer
to array [2] of long" to "pointer to array [2] of const long", since
"const long" is more cv-qualified than "long".  At this point, we
have shown that there exists a standard conversion sequence which converts
the type of the actual parameter of `func' to the type of its formal
parameter, and so it should be clear that the example is well-formed.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.


[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]
Technical Details
Message-ID: <4klir4$63e@mulga.cs.mu.OZ.AU>
Path: arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamage
References: <4ke06a$rp3@mozart.wg.icl.co.uk> <4kjqqa$bol@engnews1.Eng.Sun.COM>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamage
From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Newsgroups: comp.std.c++
Subject: Re: Array function params and const qualifier
Date: 12 Apr 1996 15:30:08 GMT
Organization: Comp Sci, University of Melbourne
Approved: clamage@eng.sun.com (comp.std.c++)
Message-ID: <4klir4$63e@mulga.cs.mu.OZ.AU>
References: <4ke06a$rp3@mozart.wg.icl.co.uk> <4kjqqa$bol@engnews1.Eng.Sun.COM>
NNTP-Posting-Host: taumet.eng.sun.com
X-Nntp-Posting-Host: munta.cs.mu.oz.au
Content-Length: 6778
X-Lines: 151
Originator: clamage@taumet