Re: Incomplete type in template parameter, complete type as
argument
On 4/8/07 1:17 PM, in article
1176052237.259633.230510@o5g2000hsb.googlegroups.com, "James Kanze"
<james.kanze@gmail.com> wrote:
On Apr 8, 3:27 am, gre...@pacbell.net (Greg Herlihy) wrote:
On 4/6/07 8:59 AM, in article
1175859305.420565.301...@y80g2000hsf.googlegroups.com, "James Kanze"
<james.ka...@gmail.com> wrote:
The tbl array attempts to instantiate the accept() function template w=
ith
two bounded arrays types (meaning that in each instance the nontype ar=
gument
is a complete type). The attempt to instantiate accept() fails (and fa=
ils
correctly) because the nontype argument used to instantiate accept() i=
n both
cases is not the same type as the type specified in accept's function
template declaration.
The instantiation doesn't fail, and if I modify the code to use
a sentinal value, rather that "begin()" and "end()", it works
perfectly. char const* [N] (with N a compile time constant) is
"compatible" with char const* [].
No, an unbounded array type is not at all "compatible" with a bounded arr=
ay
type - they are distinct and completely different types - as the followin=
g
program demonstrates (confirmed with gcc, Comeau and EDG):
template <int N, int (&a)[N]>
void f() {}
extern int s[];
int main()
{
f<1, s>(); // error: no matching function for call to 'f'
}
int s[] = { 1 };
Moving the definition of "s" before main() does compile successfully (aga=
in,
on all three C++ compilers tested), because moving the definition actuall=
y
changes the type of "s". Unlike forwardly-declared types (which have a
consistent type before and after the type is completed), the type of an
array object actually changes once the array's type is completely defined.
That is the significant point that you do not seem to have realized just
yet.
Furthermore, there is no such thing as "compatible" types when it comes t=
o
templates. Granted, a limited number of conversions is allowed for certai=
n
non-type arguments - but none are allowed for reference non-type argument=
s.
Therefore there is no conversion between an incomplete array type and any
bounded array type. Besides, if complete and incomplete array types were
compatible, then the following overloads of f() should be ambiguous:
template <int (&a)[]>
void f() {}
template <int (&a)[1]>
void f() {}
But they are not ambiguous in the least.
There's not the slightest doubt that the template function
should be instantiated.
The EDG, gcc, and Comeau C++ compilers show not the slightest doubt that =
a
complete array type cannot be passed as a template nontype argument where=
an
incomplete array type has been declared. In other words, as long as the
program tries to instantiate accept() with a array whose type is complete=
,
the program will not compile successfully.
The question centers around the notion
of when the incompleteness is resolved: in the definition of the
template, or when the template is instantiated. And it is
linked to a dependant function call---if I call a dependent
function in a template in which the parameter type is
incomplete, but the instantiation type is complete, does the
dependent fonction see the complete type, or only the
incomplete. (In the case of g++, it only sees the incomplete
type, but the question seems awkward enough that I want an
answer based on the standard.)
The answer is that the type of the argument is determined at the point th=
at
the template instantiation appears in the source file - and that is the
reason why moving the definition of the array after that point works - wh=
ile
having the definition appear prior to that point - is certain to fail.
In other words, an incomplete array type is a
different type than a complete array type:
Different, but compatible.
Either the types are the same or they are different. Since they are
different in this case - the types are incompatible.
"The declared type of an array object might be an array of unknown siz=
e and
therefore be incomplete at one point in a translation unit and complet=
e
later on;
That is exactly the phrase on which my problem hinges. The type
is incomplete when the template is defined, but it is complete
when the template is instantiated.
The accept() function template was defined with an incomplete array type =
and
therefore it can only be instantiated with an array whose type is
incomplete. Accept() may not be instantiated with any array whose type is
complete - because that array object has the wrong type to match the
declaration.
the array types at those two points (=B3array of unknown bound of
T=B2 and =B3array of N[T]=B2) are different types. The type of a point=
er to array
of unknown size, or of a type defined by a typedef declaration to be a=
n
array of unknown size, cannot be completed." [=A73.9/7]
That is, perhaps, significant. Although it doesn't actually
mention reference to array, it doesn't take much imagination to
think it this is also meant.
So in order to instantiate accept() with tab1 and tab2, it is necessar=
y to
ensure that their types are complete only after accept() has been
instantiated:
Which is totally wrong, since the types are compatible.
The program above proves the contrary - otherwise how could moving the
definition of the array object make any difference at all? And once again=
,
there is no such thing as "compatible" types.
[..]
Unfortunately, the program still fails to compile because accept() use=
s its
own nontype template argument ("keys" which is an incomplete type) as =
a
function parameter in calls to the function templates begin() and end(=
) -
both of which use the function parameter's type to deduce a complete a=
rray
type - a deduction which naturally fails when the parameter's type is
certain to be incomplete.
The problem is that accept uses its non-type template argument
in a context where a complete type is required, yes. There's no
problem instantiating accept. The problem involves whether
instantiating it with a complete type results in a complete
type.
Any attempt to pass a complete array type where an incomplete non-type
parameter is declared will not compile. And if you can produce such a
program that does compile successfully, then by all means post it.
I'd also be curious if there was a clever work-around which
worked. A priori, the compiler has all of the knowledge which
it needs, but I can't figure out a way of making it use it.
The issues are exactly as I have described them: first, passing an array
with a complete type where an array with an incomplete type is required (=
but
fixing that problem leads to the opposite situation) passing an array wit=
h
an incomplete array type where an array with a complete type is needed.
Greg
---
[ 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://www.comeaucomputing.com/csc/faq.html ]