Topic: Possible DR: template definition diagnostics (14.6/7)
Author: rani_sharoni@hotmail.com (Rani Sharoni)
Date: Fri, 6 Sep 2002 19:21:32 +0000 (UTC) Raw View
pjp@dinkumware.com ("P.J. Plauger") wrote in message news:<3d76a41d$0$17308$4c41069e@reader0.ash.ops.us.uu.net>...
> "Rani Sharoni" <rani_sharoni@hotmail.com> wrote in message
> news:df893da6.0209040502.1d1f8d5b@posting.google.com...
>
> > I'll just summarize my main point.
> > It seems that the C++ language is defined in such way that it isn't
> > possible, in general, to tell whether given piece of C++ code is
> > well-formed.
> > Isn't it problematic to define the language in such way?
>
> Yes.
Thanks for the answer.
Couple of questions:
1) Is the following code ill-formed?
template<typename T>
struct A
{
template<typename U>
struct C1 { static const bool value = false; };
typedef int X[C1<T>::value != C1<T>::value];
};
EDG didn't issue any diagnostics.
2) Is there any well-formed instantiation for the following template?
template<typename T>
struct A
{
template<typename U>
struct C1 { static const bool value = false; };
template<typename U>
struct C2 { static const bool value = false; };
typedef int X[C1<T>::value != C2<T>::value];
};
I tried the following specialization but EDG still rejected the instantiation:
template<typename T>
template<typename U>
struct A<T>::template C1<U*>
{
static const bool value = true;
};
A<int*> x;
Notice that EDG **did** found the following code ill-formed:
template<typename T>
struct A
{
struct C1 { static const bool value = false; };
struct C2 { static const bool value = false; };
typedef int X[C1::value != C2::value];
};
I will appreciate any answers to the above questions.
Thanks,
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: rani_sharoni@hotmail.com (Rani Sharoni)
Date: Sun, 1 Sep 2002 10:34:02 CST Raw View
Hello All,
I recently posted this issue to c.l.c++.m, but did not receive any
replies. I thought that maybe this newsgroup is more appropriate for
such issues, and I will appreciate any comments.
Lately I have come to think that 14.6/7 is defective and should be
rephrased. The problem with 14.6/7 is that it defines when template
definition is ill-formed in way that we can't, in general, verify.
First I'll quote 14.6/7:
Knowing which names are type names allows the syntax of every template
definition to be checked. No diagnostic shall be issued for a template
definition for which a valid specialization can be generated. If no
valid specialization can be generated for a template definition, and
that template is not instantiated, the template definition is
ill-formed, no diagnostic required. [Note: if a template is
instantiated, errors will be diagnosed according to the other rules in
this Standard. Exactly when these errors are diagnosed is a quality of
implementation issue. ]
Can we check, in general, whether no valid specialization can be
generated for a template definition? IMHO the answer is NO and here is
some "proof":
template<typename T>
struct C1 { static const bool value = /* ... */ };
template<typename T>
struct C2 { static const bool value = /* ... */ };
template<typename T>
struct AssertNotSameMetaFunction
{
typedef int A[C1<T>::value != C2<T>::value];
};
C1 and C2 are (meta) functions that map C++ types (infinite countable
set) to bool. It's known that in general it isn't possible to decide
whether such C1 and C2 are equal. For any given verifying algorithm
there are C1 and C2 which fail it. The compiler can never tell, in
general, whether the above code is ill-formed because it is so if C1
equals C2.
I don't feel comfortable knowing that, by definition, the language
doesn't enable its compilers to diagnose ill-formed code.
Compilers today seem to be very limited in diagnosing even "simple"
cases:
template<typename T>
int f1(T *p) { return p;}
template<typename T>
int* f2(T **p) { return p;}
According to 14.6/7 both templates definitions are obviously
ill-formed because no valid instances can be generated from them. From
the compilers I tried EDG is the only one that diagnosed f1's error
and no compiler found f2's error.
I think that "quality of implementation", as mentioned in 14.6/7,
really belongs to the field of compiler warnings (or lint like tools)
and not the C++ language mostly because the "implementation" will
never have enough "quality" to decide whether the code is well-formed.
Notice that 14.6/7 is the only place in the C++ standard where
"quality of implementation" is mentioned in such way (decide whether
the code is well-formed).
My suggestion is to require diagnostics only for non-depended code,
which is the same as non-template function definition diagnostics.
Depended-code diagnostic shouldn't be allowed until POI (except for
maybe names that should be bound at the point of template definition).
The template definition will be well-formed even if no specialization
can be generated for it and that template is not instantiated. The
compiler (or other tools) can try to help the template writer with
appropriate warnings in cases like the above f1 and f2.
Again, I will appreciate any comments.
Thanks,
Rani Sharoni
---
[ 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: Allan_W@my-dejanews.com (Allan W)
Date: Wed, 4 Sep 2002 02:10:49 +0000 (UTC) Raw View
template<typename T> struct C1 { static const bool value = true };
template<typename T> struct C2 { static const bool value = true };
template<typename T> struct AssertNotSameMetaFunction
{ typedef int A[C1<T>::value != C2<T>::value]; }
> C1 and C2 are (meta) functions that map C++ types (infinite countable
> set) to bool. It's known that in general it isn't possible to decide
> whether such C1 and C2 are equal. For any given verifying algorithm
> there are C1 and C2 which fail it. The compiler can never tell, in
> general, whether the above code is ill-formed because it is so if C1
> equals C2.
...and there are specializations of C1 and C2 (and certainly of
AssertNotSameMetaFunction) that mean they ARE valid.
// Make int work
template<>struct C2<int> { static const bool value = false; }
// Make long work
template<> struct AssertNotSameMetaFunction<long>
{ typedef int A[1]; }
> I don't feel comfortable knowing that, by definition, the language
> doesn't enable its compilers to diagnose ill-formed code.
I think one of the points that the standard made, was that in many
cases it depends on how you instantiate the code. Your class is
well-formed for int, now; the compiler couldn't know that while it
was first parsing your Assert struct. More realistically, a template
could easily work well with Random iterators but not Forward
iterators, or fail if the class instantiated isn't CopyConstructible.
That's a far cry from "doesn't enable its compilers to diagnose
ill-formed code." The phrase "no diagnostic required" is different
from "no diagnostic allowed," the first means that it's up to the
implementors to decide, while the latter would mean what you seem
to think it means.
> I think that "quality of implementation", as mentioned in 14.6/7,
> really belongs to the field of compiler warnings (or lint like tools)
Most compiler vendors today will tell you that you don't need a lint-
like tool, because their compiler has it built-in (at least at the
maximum warning setting).
Whether this is true or not is another issue. The point is, if lint
can issue a warning message, there's no reason why a compiler can't
do the same.
> and not the C++ language mostly because the "implementation" will
> never have enough "quality" to decide whether the code is well-formed.
But if it's ill formed and the compiler isn't required to issue a
diagnostic, then it's up to the individual compiler to do so or not.
That is the very definition of "quality of implementation" -- if one
compiler issued a helpful warning and the other didn't, most people
would say the first had better quality.
> My suggestion is to require diagnostics only for non-depended code,
> which is the same as non-template function definition diagnostics.
> Depended-code diagnostic shouldn't be allowed until POI (except for
> maybe names that should be bound at the point of template definition).
>
> The template definition will be well-formed even if no specialization
> can be generated for it and that template is not instantiated. The
> compiler (or other tools) can try to help the template writer with
> appropriate warnings in cases like the above f1 and f2.
I think you're saying that with code like this:
template<typename A>struct BadClass
{ int int; A A; int A; }; // <- Point A
BadClass<int>b; // <- Point B
that the compiler would be required to generate an error at point B,
but wouldn't be allowed to at Point A.
I don't like it.
---
[ 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: rani_sharoni@hotmail.com (Rani Sharoni)
Date: Wed, 4 Sep 2002 21:47:59 +0000 (UTC) Raw View
Allan_W@my-dejanews.com (Allan W) wrote in message news:<23b84d65.0209031715.6654ee54@posting.google.com>...
> ...and there are specializations of C1 and C2 (and certainly of
> AssertNotSameMetaFunction) that mean they ARE valid.
> [...]
I agree that I made a mistake since C1 or C2 can be specialized in
away that make AssertNotSameMetaFunction well-formed but directly
specializing AssertNotSameMetaFunction is not relevant.
The following code fixes my "proof" (now C1 and C2 can't be
specialized):
template<typename T>
struct AssertNotSameMetaFunction
{
void f()
{
struct C1 { enum { value = false }; };
struct C2 { enum { value = false }; };
typedef int A[C1::value != C2::value];
}
};
Notice that C1 and C2 are still meta-functions of T. EDG **amazingly**
diagnose the above code and found that it is ill-formed but after
replacing "value = false" with "value = sizeof(T)" for both C1 and C2
EDG gave no diagnostic.
>
> > I think that "quality of implementation", as mentioned in 14.6/7,
> > really belongs to the field of compiler warnings (or lint like tools)
>
> Most compiler vendors today will tell you that you don't need a lint-
> like tool, because their compiler has it built-in (at least at the
> maximum warning setting).
>
lint is not the issue. I think that it's important that the programmer
will be notified that something is wrong with his program even if the
program is well-formed. For example all the compilers I know warn
(diagnose) about the following well formed code:
void f()
{
int *p;
int y = *p; // local variable 'p' used without having been
initialized
}
This code is far more "ill-formed" because unlike template which is
not instantiate it effects the generated program. I guess that the
standard allows the above f() (with undefined behavior label) because,
in general, it isn't possible to diagnose such cases in compile/link
time.
> > and not the C++ language mostly because the "implementation" will
> > never have enough "quality" to decide whether the code is well-formed.
>
> But if it's ill formed and the compiler isn't required to issue a
> diagnostic, then it's up to the individual compiler to do so or not.
> That is the very definition of "quality of implementation" -- if one
> compiler issued a helpful warning and the other didn't, most people
> would say the first had better quality.
I didn't claim that even if the code is ill-formed no diagnostic is
allowed but according to the suggestion bellow the code can be
well-formed at the point of definition and ill-formed at POI just like
the above f is well-formed at compile time and ill-formed at run time.
>
> > My suggestion is to require diagnostics only for non-depended code,
> > which is the same as non-template function definition diagnostics.
> > Depended-code diagnostic shouldn't be allowed until POI (except for
> > maybe names that should be bound at the point of template definition).
> >
> > [...]
>
> I think you're saying that with code like this:
>
> template<typename A>struct BadClass
> { int int; A A; int A; }; // <- Point A
> BadClass<int>b; // <- Point B
>
template<typename A> struct BadClass
{
int int; // non-depended code diagnostic required
A A; // name binding error diagnostic required
int A; // name binding error diagnostic required
};
> that the compiler would be required to generate an error at point B,
> but wouldn't be allowed to at Point A.
The compiler can issue a warnings.
I'll just summarize my main point.
It seems that the C++ language is defined in such way that it isn't
possible, in general, to tell whether given piece of C++ code is
well-formed.
Isn't it problematic to define the language in such way?
Thanks,
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: pjp@dinkumware.com ("P.J. Plauger")
Date: Thu, 5 Sep 2002 01:02:43 +0000 (UTC) Raw View
"Rani Sharoni" <rani_sharoni@hotmail.com> wrote in message
news:df893da6.0209040502.1d1f8d5b@posting.google.com...
> I'll just summarize my main point.
> It seems that the C++ language is defined in such way that it isn't
> possible, in general, to tell whether given piece of C++ code is
> well-formed.
> Isn't it problematic to define the language in such way?
Yes.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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 ]