Topic: 14.7.1 clarification/rationale?
Author: rani_sharoni@hotmail.com (Rani Sharoni)
Date: Thu, 31 Oct 2002 21:33:44 CST Raw View
agurtovoy@meta-comm.com (Aleksey Gurtovoy) wrote in message news:<81667c9.0210272205.3a5b2a25@posting.google.com>...
> Consider the following:
>
> template< typename U > void test(U*);
>
> template< typename T > struct something
> {
> T member;
> };
>
> struct incomplete;
>
> void foo()
> {
> test(static_cast<incomplete*>(0)); // #1
> test(static_cast<something<incomplete>*>(0)); // #2
> }
>
> Should the compiler accept the line #2, reject it as ill-formed, or is
> the behavior unspecified?
>
> 14.7.1 [temp.inst], paragraphs 4 & 5 seem to be saying the latter
> (unspecified behavior), and at least one EDG-based compiler actually
> rejects the above code because it tries to instantiate
> 'something<incomplete>' in order to perform overload resolution on
> 'something<incomplete>*'.
>
> Could somebody with internal knowledge of this section answer these
> questions/provide a rationale for it?
>
I'm not somebody with internal knowledge but I'll try my best.
I think that the main reason behind 14.7.1/5 is the fact that it's hard to
define the conditions of when the instantiation is not needed for the result
of the overload resolution.
Consider the following:
struct S {};
template <class T> struct B
{
T member;
typedef B type;
};
template <class T> struct A : B<T> {};
struct incomplete;
long *f(S *);
char *f(void *);
char *g(A<incomplete> *p)
{
return f(p);
}
It seems that the above code also fits 14.7.1/5 because void f(void *) is
the only viable function for overloading but *all* the compilers I tested
(EDG, VC, GCC and BCC) has instantiated A<incomplete> resulting with
compilation error.
It's seems that in this case the implementations are not "psychic" enough to
decide that the instantiation is unnecessary for the overload resolution.
Just think how the compiler can know that B<incomplete> is not derived from
S without instantiating it.
I think that EDG is correct with the strict interpretation of 14.7.1/5
because it leads to more portable code.
Is the standard is too relaxed regarding this issue and instantiation should
be required in such cases (or maybe specified more exact conditions)?
Rani
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: agurtovoy@meta-comm.com (Aleksey Gurtovoy)
Date: Mon, 28 Oct 2002 10:58:13 CST Raw View
Consider the following:
template< typename U > void test(U*);
template< typename T > struct something
{
T member;
};
struct incomplete;
void foo()
{
test(static_cast<incomplete*>(0)); // #1
test(static_cast<something<incomplete>*>(0)); // #2
}
Should the compiler accept the line #2, reject it as ill-formed, or is
the behavior unspecified?
14.7.1 [temp.inst], paragraphs 4 & 5 seem to be saying the latter
(unspecified behavior), and at least one EDG-based compiler actually
rejects the above code because it tries to instantiate
'something<incomplete>' in order to perform overload resolution on
'something<incomplete>*'.
Could somebody with internal knowledge of this section answer these
questions/provide a rationale for it?
TIA,
Aleksey
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
Author: agurtovoy@meta-comm.com (Aleksey Gurtovoy)
Date: Mon, 4 Nov 2002 09:42:34 +0000 (UTC) Raw View
Rani Sharoni wrote in message news:<df893da6.0210311804.4743819c@posting.google.com>...
> agurtovoy@meta-comm.com (Aleksey Gurtovoy) wrote in message news:<81667c9.0210272205.3a5b2a25@posting.google.com>...
> > Consider the following:
> >
> > template< typename U > void test(U*);
> >
> > template< typename T > struct something
> > {
> > T member;
> > };
> >
> > struct incomplete;
> >
> > void foo()
> > {
> > test(static_cast<incomplete*>(0)); // #1
> > test(static_cast<something<incomplete>*>(0)); // #2
> > }
> >
> > Should the compiler accept the line #2, reject it as ill-formed, or is
> > the behavior unspecified?
> >
> > 14.7.1 [temp.inst], paragraphs 4 & 5 seem to be saying the latter
> > (unspecified behavior), and at least one EDG-based compiler actually
> > rejects the above code because it tries to instantiate
> > 'something<incomplete>' in order to perform overload resolution on
> > 'something<incomplete>*'.
> >
> > Could somebody with internal knowledge of this section answer these
> > questions/provide a rationale for it?
> >
> I'm not somebody with internal knowledge but I'll try my best.
Well, thank you for the reply.
> I think that the main reason behind 14.7.1/5 is the fact that it's hard to
> define the conditions of when the instantiation is not needed for the result
> of the overload resolution.
>
> Consider the following:
>
> struct S {};
>
> template <class T> struct B
> {
> T member;
> typedef B type;
> };
>
> template <class T> struct A : B<T> {};
>
> struct incomplete;
>
> long *f(S *);
> char *f(void *);
>
> char *g(A<incomplete> *p)
> {
> return f(p);
> }
>
> It seems that the above code also fits 14.7.1/5 because void f(void *) is
> the only viable function for overloading but *all* the compilers I tested
> (EDG, VC, GCC and BCC) has instantiated A<incomplete> resulting with
> compilation error.
>
> It's seems that in this case the implementations are not "psychic" enough to
> decide that the instantiation is unnecessary for the overload resolution.
> Just think how the compiler can know that B<incomplete> is not derived from
> S without instantiating it.
It cannot, as it can't in either of these cases:
1)
struct S {};
struct A;
long *f(S *);
char *f(void *);
char *g(A *p)
{
return f(p);
}
2)
struct S {};
template <class T> struct B
{
T member;
typedef B type;
};
template <class T> struct A;
struct incomplete;
long *f(S *);
char *f(void *);
char *g(A<incomplete> *p)
{
return f(p);
}
template <class T> struct A : B<T> {};
Yet the above is well-formed and happily accepted by all compilers,
including the one that promted my original post.
IMO the second example is already strong enough reason to dislike
14.7.1/5 - depending on whenever the definition of 'A' is included
after or before the definition of 'g' your (perfectly reasonable) code
will either compile and run as expected, or yield a compilation error
that is bogus.
> I think that EDG is correct with the strict interpretation of 14.7.1/5
> because it leads to more portable code.
I think that 14.7.1/5 imposes a draconic rule, the consequences of
which we happen to not encounter widely yet because so far there is
only one compiler that exercises the freedom granted by that paragraph
in full. I am frightened that other compilers might follow the
practice and make our life miserable ;). Not to mention the
portability nightmares of the unspecified behavior on such a major
point.
> Is the standard is too relaxed regarding this issue and instantiation should
> be required in such cases (or maybe specified more exact conditions)?
IMO at least the latter, e.g. this should be definitely well-formed:
template< typename T > struct A
{
T x;
};
struct incomplete;
void foo(A<incomplete> const&);
void forward_foo(A<incomplete> const& a)
{
foo(a);
}
Aleksey
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]