Topic: C++0x static_assert(0, "") within a non-instantiated template


Author: greghe@pacbell.net (Greg Herlihy)
Date: Tue, 3 Jul 2007 13:04:20 GMT
Raw View


On 6/29/07 8:26 AM, in article
1183113163.342662.146830@n60g2000hse.googlegroups.com, "Vladimir Marko"
<swelef@post.sk> wrote:

> On 29 Jun, 07:35, Greg Herlihy <gre...@pacbell.net> wrote:
>> On Jun 23, 9:54 am, nore...@this.is.invalid (Niels Dekker - no return
>>=20
>>> But unfortunately both BOOST_STATIC_ASSERT calls appear to be
>>> ill-formed, even within an uninstantiated template, as Gennaro Prota
>>> explained to me (by e-mail).  Quoting the current Draft, 14.6, Name
>>> resolution [temp.res]:
>>>   "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.
>>> "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2284.pdf
>>=20
>> The compiler does generate a valid specialization in this situation -
>> because if the "SpecializeMePlease" template definition were ill-forme=
d,
>> then no specialization would have been generated and the
>> BOOST_STATIC_ASSERT would never have been evaluated. In other words, i=
n
>> order for BOOST_STATIC_ASSERT(sizeof(T)=3D=3D0) to be ill-formed, the
>> "SpecializeMePlease" specialization that led to its instantiation - mu=
st be
>> valid.
>=20
> With all respect, this is nonsense. The compiler does not generate
> a valid specialization, because none exists. The template definition
> is ill-formed even without ever being instantiated (the quote provided
> is very clear about it). And, finally, the compiler often needs to
> instantiate a template specialization to find out _if_ it's ill-
> formed,
> making your last sentence rather ridiculous.

A static assert with a non-dependent expression (that evaluates to false)
does indeed render the template definition in which it appears, ill-forme=
d.
Moreover, the compiler is not obligated to diagnose this problem - unless
and until the template is instantiated.

Now, a static assert with a value-dependent expression (which subsequentl=
y
evaluates to false in a template specialization) renders the template
specialization - and only the specialization - ill-formed. Moreover an
ill-formed template specialization does not mean that the template
definition used to generate it was also ill-formed. On the contrary, beca=
use
only a well-formed template definition can generate a template
specialization successfully, the template definition must have been
well-formed in order to have generated an ill-formed specialization. Or t=
o
put it another way, the specialization could not be ill-formed - if it di=
d
not exist.=20

So the only question to resolve here is whether sizeof(T)=3D=3D0 is a
value-dependent expression or not. Because if the expression is not value
dependent, then the static assert would be evaluated in the context of th=
e
template definition. Otherwise, if the expression is value-dependent, the=
n
its evaluation  would be deferred until a template specialization.

According to the Standard, the expression sizeof(T) is value-dependent:

"Expressions of the following form are value-dependent if the
unary-expression is type-dependent or the type-id is dependent (even if
sizeof unary-expression and sizeof (type-id) are not type-dependent):

    sizeof unary-expression
    sizeof (type-id )  [=A714.6.2.3/2]

Moreover, since "a constant expression is value-dependent if any
subexpression is value-dependent", it follows that sizeof(T)=3D=3D0 must
value-dependent because its subexpression, sizeof(T), is value-dependent.

> While the compilers are likely to accept the code, the _language_
> says the template definition is ill-formed. There is a workaround,
> though:
>=20
> template <typename>
> struct always_false { static const bool value =3D false; };
>=20
> template <typename T>
> class specialize_me
> {
>     static_assert(always_false<T>::value,"don't instantiate this
> template");
> };
>=20
> Here, we could provide a specialization of always_false to make
> it possible to generate a valid instantiation of specialize_me, thus
> the definition of specialize_me can't be deemed ill-formed.

There is no material difference between the static_assert in the above
example and a static_assert(sizeof(T)=3D=3D0). In both cases, the express=
ion
being asserted is value-dependent on a template type argument, T. Therefo=
re
in both cases the evaluation of the static_assert is deferred until the
specialize_me template is instantiated (if ever). So when either template=
 is
instantiated: a well-formed template definition winds up generating a val=
id,
but ill-formed specialization.

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                      ]





Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Tue, 3 Jul 2007 08:08:55 CST
Raw View
Daniel Kr  gler ha scritto:
>
> I'm not convinced. What I see, if I interpret 14.6/7 strictly, that a
> cute
> compiler could recognize that it can distinguish two cases:
>
> 1) sizeof(T) is wellformed (because the type is complete): Here always
> results: sizeof(T) > 0. So the assertion must always be wrong and for
> no complete type can the template be spezialized.
>
> 2) sizeof(T) is *not* wellformed for any incomplete type, thus for no
> incomplete type can the template be spezialized.
>
> So, the compiler can (theoretically) proof, that only one of these
> cases
> is possible and that in neither of them a valid specialization could
> be
> generated. So the template definition is ill-formed in all cases and
> the
> "no-diagnostic"-situation of 14.6/7 applies.
>
> Is such an interpretation valid?
>

You've got a point. I agree that, taken to the letter, 14.6/7 would make
the definition ill-formed. However, I have the impression that the
intent of the clause was not to forbid this case. The statement is only
about "checking syntax" and non-dependent types which are incomplete at
point of definition.

Let's consider a slightly simpler case, for sake of explanation. Be
exprT any *value-dependent* expression convertible to bool, well-defined
for every T. Then consider a template definition including

   static_assert(exprT, "");

If exprT *by a mere accident* happens to always evaluate to false for
every T, then the program immediately becomes ill-formed even if the
compiler might not even be able to actually detect that and even if the
template is not instantiated! I find this very unfortunate. Allowing
no-diagnostic is a very little consolation, IMHO.

Bear in mind, that if the constexpr proposal is accepted, exprT can be
arbitrarily complex, so we cannot expect the average compiler to
actually enforce the rule.

I propose to amend [dcl.dcl] para 4, so to explicit mention the case
where the expression in a static_assert is value-dependent. In such
case, the decision about the well-formedness shall be deferred to the
point of instantiation even if the compiler could theoretically be able
to determine that the expression is actually constant at the point of
declaration. That might actually make life easier for compiler, without
ill-affecting the usefulness of static_assert.

Any thoughts?

Ganesh

---
[ 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                      ]





Author: greghe@pacbell.net (Greg Herlihy)
Date: Tue, 3 Jul 2007 13:13:29 GMT
Raw View


On 7/1/07 8:23 AM, in article
1183291569.419981.61530@c77g2000hse.googlegroups.com, "Daniel Kr=FCgler"
<daniel.kruegler@googlemail.com> wrote:

> On 29 Jun., 17:26, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
> wrote:
>> So, it's not true that sizeof(T) > 0 for *every* type. It's true only =
for
>> *complete* types (those that can be instantiated to object). The
>> compiler cannot "optimize" the expression sizeof(T) =3D=3D 0 assuming =
that
>> it always evaluates to false, because it might be ill-formed for some =
T
>> (for example: void). This is enough to force the compiler to treat the
>> expression as type-dependent.
>=20
> I'm not convinced. What I see, if I interpret 14.6/7 strictly, that a
> cute
> compiler could recognize that it can distinguish two cases:
>=20
> 1) sizeof(T) is wellformed (because the type is complete): Here always
> results: sizeof(T) > 0. So the assertion must always be wrong and for
> no complete type can the template be spezialized.

The entire purpose of the static_assert( sizeof(T) =3D=3D 0) is to ensure=
 that
any specialization of the template will be ill-formed - but to do so in s=
uch
a way (specifically: with a value-dependent expression) that the template
definition itself remains well-formed. Because as long as the template
definition is well-formed (meaning the compiler is able to look up all
non-dependent names in the template definition), then the compiler will b=
e
able to generate a valid (though not necessarily, well-formed) template
specialization from it. And that is exactly what happens here, the compil=
er
is able to generate a specialize_me specialization for any type T. Now, t=
he
specialization turns out to be ill-formed (for one reason or another), bu=
t
the ill-formedness of the specialization has no bearing on the
well-formedness of the template definition that generated it.

> 2) sizeof(T) is *not* wellformed for any incomplete type, thus for no
> incomplete type can the template be spezialized.

On the contrary - there is no type T for which a specialization cannot be
generated in this example. There is after all no requirement anywhere in =
the
C++ Standard that states that a valid template specialization must also b=
e
well-formed. A "valid" specialization is simply one that the compiler can
-generate- from the template definition without an error; there is no
requirement that the compiler, when it subsequently -evaluates- the
specialization, must find it to be well-formed.
=20
> So, the compiler can (theoretically) proof, that only one of these
> cases
> is possible and that in neither of them a valid specialization could
> be
> generated. So the template definition is ill-formed in all cases and
> the
> "no-diagnostic"-situation of 14.6/7 applies.
>=20
> Is such an interpretation valid?

No. The mistake here is equating an "invalid" specialization with one tha=
t
is ill-formed. In reality, the two describe distinct stages in the
processing of a template specialization, one applies to its generation an=
d
the other to its subsequent evaluation.

After all, the very first time that a compiler parses a template definiti=
on
it can easily tell whether the definition is well-formed or not (and if t=
he
definition is ill-formed, a diagnostic is required at that point.)
Otherwise, the compiler generates a valid specialization for the provided
template type parameters. This specialization is then evaluated in the
context of its point of instantiation.

This distinction between the generation and the evaluation of a template
specialization can be demonstrated simply by instantiating a value-depend=
ent
static_assert or a value-dependent BOOST_STATIC_ASSERT (which, somewhat
ironically, relies on taking the sizeof an incomplete type to render the
program ill-formed when the asserted expression is not true) and noting t=
he
error that the compiler reports. Now, if the compiler reports that the
template specialization (and not the template definition) is ill-formed,
then it must be the case that the compiler was able to generate a valid
specialization from the template definition - otherwise a failure to do s=
o
would have required a diagnostic at the point.

Or to put it another way: a template definition is not ill-formed even if
every specialization of that template is ill-formed. In fact, it proves j=
ust
the opposite: that an ill-formed template specialization must have a
well-formed template definition - because an ill-formed template definiti=
on
would have been unable to generate any template specialization - and a
nonexistent specialization obviously cannot be ill-formed.

Greg

=20

---
[ 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                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 3 Jul 2007 13:14:49 GMT
Raw View
Greg Herlihy ha scritto:
> Or to put it another way: a template definition is not ill-formed even
> if
> every specialization of that template is ill-formed. In fact, it
> proves just
> the opposite: that an ill-formed template specialization must have a
> well-formed template definition - because an ill-formed template
> definition
> would have been unable to generate any template specialization - and a
> specialization that was never generated - cannot be ill-formed.
>

Ah! Insightful. So you are arguing that the requirement "if no *valid*
specialization can be generated" must not be read as "if no
*well-formed* specialization can be generated", correct?

"Knowing which names are type names allows the syntax of every template
definition to be checked". If the syntax of the template definition is
wrong, of course we cannot generate any "valid" specialization. Only
once we have a "valid" specialization we can check for well-formedness,
but that is a different step that occurs at a later stage, precisely at
the point of instantiation. In fact: "no diagnostic shall be issued for
a template definition for which a valid specialization can be generated"
even the such "valid" specialization happens to be ill-formed.

This makes a whole lot sense to me. However, if that interpretation is
correct, then we must reconsider the very beginning of this discussion,
because it would mean that the definition:

  template <typename T> void SpecializeMePlease(T) {
    static_assert(0, "Do not instantiate this template");
  }

is indeed well-formed! Personally I'd like that, because it makes thing
soo much simple.

Am I missing something?

Ganesh

---
[ 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                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 3 Jul 2007 16:33:07 GMT
Raw View
Daniel Kr=C3=BCgler ha scritto:
> On 1 Jul., 16:22, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>> No. The diagnostic is still required: the compiler should complain tha=
t
>> the sizeof operator is applied to an invalid type ([expr.sizeof] para
>> 1). So the program is ill-formed in both cases, but reason of
>> ill-formedness is different: in order to provide the correct diagnosti=
c
>> the compiler must treat the expression as type-dependent.
>=20
> OK, I see what you mean and your argument seem to the following:
>=20
> Given any infeasible argument TFalse for T in the expression
> sizeof(T)
> has to be diagnosed ([expr.sizeof], "[..] The sizeof operator shall
> not be
> applied to an expression that has function or incomplete type,[..]).
> This requirement contradicts the assertion of [temp.res]/7 "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."
>=20
> Taking the position of devil's advocate I say, that [temp.res]/7
> does not say anything about the reasons, why the specialization
> could not be generated and this could also happen due to some
> usually *diagnosable* reason. But in this special case the standard
> allows that the failure need not be diagnosed.
>=20
> Is this a valid position?

As noticed by Vladimir Marko and myself in other posts which you may
have not read yet, the key point here seems to be what actually "valid
specialization" means in [temp.res]/7. If you agree with that, I suggest
you read those other posts and possibly reply to them, in order to keep
the discussion more focused.

Ganesh

---
[ 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                      ]





Author: James Dennett <jdennett@acm.org>
Date: Tue, 3 Jul 2007 22:49:45 CST
Raw View
Greg Herlihy wrote:
>
>
> On 7/1/07 8:23 AM, in article
> 1183291569.419981.61530@c77g2000hse.googlegroups.com, "Daniel Kr   gler"
> <daniel.kruegler@googlemail.com> wrote:
>
>> On 29 Jun., 17:26, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
>> wrote:
>>> So, it's not true that sizeof(T) > 0 for *every* type. It's true only for
>>> *complete* types (those that can be instantiated to object). The
>>> compiler cannot "optimize" the expression sizeof(T) == 0 assuming that
>>> it always evaluates to false, because it might be ill-formed for some T
>>> (for example: void). This is enough to force the compiler to treat the
>>> expression as type-dependent.
>> I'm not convinced. What I see, if I interpret 14.6/7 strictly, that a
>> cute
>> compiler could recognize that it can distinguish two cases:
>>
>> 1) sizeof(T) is wellformed (because the type is complete): Here always
>> results: sizeof(T) > 0. So the assertion must always be wrong and for
>> no complete type can the template be spezialized.
>
> The entire purpose of the static_assert( sizeof(T) == 0) is to ensure that
> any specialization of the template will be ill-formed - but to do so in such
> a way (specifically: with a value-dependent expression) that the template
> definition itself remains well-formed.

Yes, that was the intention; this thread is about whether
that has been achieved.

Given that a template definition with no valid (which implies
well-formed) specialization exists is itself ill-formed, it
seems that from a standards perspective the goal has *not*
been achieved, and the technique used is not guaranteed to
work.

> Because as long as the template
> definition is well-formed (meaning the compiler is able to look up all
> non-dependent names in the template definition), then the compiler will be
> able to generate a valid (though not necessarily, well-formed) template
> specialization from it.

A valid specialization is a well-formed one.  I'm not aware
of any part of the standard which allows for ill-formed but
"valid" specializations.  If you are, this is a good place
to cite it.

> And that is exactly what happens here, the compiler
> is able to generate a specialize_me specialization for any type T. Now, the
> specialization turns out to be ill-formed (for one reason or another), but
> the ill-formedness of the specialization has no bearing on the
> well-formedness of the template definition that generated it.

But many of us believe that it does.  Are you sure that you
are not assuming your own conclusion?

>> 2) sizeof(T) is *not* wellformed for any incomplete type, thus for no
>> incomplete type can the template be spezialized.
>
> On the contrary - there is no type T for which a specialization cannot be
> generated in this example. There is after all no requirement anywhere in the
> C++ Standard that states that a valid template specialization must also be
> well-formed. A "valid" specialization is simply one that the compiler can
> -generate- from the template definition without an error; there is no
> requirement that the compiler, when it subsequently -evaluates- the
> specialization, must find it to be well-formed.

This is interesting theory, but templates aren't "evaluated",
and I know of no concept in the C++ standard of a template
specialization being "valid" but ill-formed.  Ill-formed
entities are not valid.

>> So, the compiler can (theoretically) proof, that only one of these
>> cases
>> is possible and that in neither of them a valid specialization could
>> be
>> generated. So the template definition is ill-formed in all cases and
>> the
>> "no-diagnostic"-situation of 14.6/7 applies.
>>
>> Is such an interpretation valid?
>
> No. The mistake here is equating an "invalid" specialization with one that
> is ill-formed. In reality, the two describe distinct stages in the
> processing of a template specialization, one applies to its generation and
> the other to its subsequent evaluation.

Do you have any references to the standard supporting such
a claim?

Your assumption that valid specializations can be ill-formed
is a very novel one, though I'm not sure it's persuasive enough
to justify clarifying this in the standard.

> After all, the very first time that a compiler parses a template definition
> it can easily tell whether the definition is well-formed or not (and if the
> definition is ill-formed, a diagnostic is required at that point.)

Again, this assumes its own conclusion, based on what appears
to be your own notion of what a well-formed template definition
is.  The standard *explicitly* says that a template definition
with no valid specializations is ill-formed; determining that
no valid specialization exists is possible only in some cases.

> Otherwise, the compiler generates a valid specialization for the provided
> template type parameters. This specialization is then evaluated in the
> context of its point of instantiation.

Where is this notion of "evaluated" coming from?

> This distinction between the generation and the evaluation of a template
> specialization can be demonstrated simply by instantiating a value-dependent
> static_assert or a value-dependent BOOST_STATIC_ASSERT (which, somewhat
> ironically, relies on taking the sizeof an incomplete type to render the
> program ill-formed when the asserted expression is not true) and noting the
> error that the compiler reports. Now, if the compiler reports that the
> template specialization (and not the template definition) is ill-formed,
> then it must be the case that the compiler was able to generate a valid
> specialization from the template definition - otherwise a failure to do so
> would have required a diagnostic at the point.

Your conclusion does not follow.  (And basing what's right on
what specific compilers happen to say in their diagnostics is
error prone at best.)

There are two cases: (a) the template is instantiated, and
(b) it is not.  In case (a), the specialization will be invalid,
and diagnostics may be required as described elsewhere.  In case
(b), the template definition is invalid, no diagnostic required.
In neither case is the compiler required to accept the code.

> Or to put it another way: a template definition is not ill-formed even if
> every specialization of that template is ill-formed.

But the standard says it is, so it is.  If every specialization
is invalid (which is synonymous in this context with ill-formed)
then the template definition is ill-formed unless it is
instantiated (and in the latter case the program is ill-formed
because it contains an invalid instantiation).

> In fact, it proves just
> the opposite: that an ill-formed template specialization must have a
> well-formed template definition - because an ill-formed template definition
> would have been unable to generate any template specialization - and a
> nonexistent specialization obviously cannot be ill-formed.

14.6/7 (in [temp.res]) does vaguely support this, but note that
its text making the template definition ill-formed applies only
if the template is *not* instantiated.  (In some sense, "observing"
the template definition by instantiating it alters whether it is
well-formed or not.)  Of course, a program which instantiates
a template that has no *valid* instantiation will be ill-formed,
and the implementation is permitted to issue any diagnostics
it wishes as well as refusing to translate the program.

-- James

---
[ 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                      ]





Author: greghe@pacbell.net (Greg Herlihy)
Date: Wed, 4 Jul 2007 03:52:50 GMT
Raw View
On 7/3/07 6:14 AM, in article rLpii.54558$U01.543236@twister1.libero.it,
"Alberto Ganesh Barbati" <AlbertoBarbati@libero.it> wrote:

> Greg Herlihy ha scritto:
>> Or to put it another way: a template definition is not ill-formed even
>> if
>> every specialization of that template is ill-formed. In fact, it
>> proves just
>> the opposite: that an ill-formed template specialization must have a
>> well-formed template definition - because an ill-formed template
>> definition
>> would have been unable to generate any template specialization - and a
>> specialization that was never generated - cannot be ill-formed.
>=20
> Ah! Insightful. So you are arguing that the requirement "if no *valid*
> specialization can be generated" must not be read as "if no
> *well-formed* specialization can be generated", correct?

Exactly.
=20
> This makes a whole lot sense to me. However, if that interpretation is
> correct, then we must reconsider the very beginning of this discussion,
> because it would mean that the definition:
>=20
>   template <typename T> void SpecializeMePlease(T) {
>     static_assert(0, "Do not instantiate this template");
>   }
>=20
> is indeed well-formed! Personally I'd like that, because it makes thing
> soo much simple.

No, the SpecializeMePlease template definition is ill-formed in your exam=
ple
because the expression used in the static_assert test, is non-dependent
(whereas any expression containing a sizeof(T) is always value-dependent,
see =A714.6.2.3). And a non-dependent expression is evaluated in the cont=
ext
of the template definition. Since the static_assert (obviously) fails, th=
e
template definition itself is ill-formed (and no template specialization =
can
be generated from it).

Now, if the SpecializeMePlease template is never instantiated, the compil=
er
is not obligated to evaluate the static_assert and diagnose the fact that
the template definition is ill-formed. But whether or not the compiler
evaluates the static_assert in that situation, the program is nevertheles=
s,
ill-formed.=20

On the other hand, if the SpecializeMePlease template is instantiated, th=
en
the compiler must evaluate the static_assert and at that point must diagn=
ose
the fact that SpecializeMePlease's template definition is ill-formed. And=
 it
is the ill-formedness of the template definition that prevents any valid
specialization of it, from ever being generated.

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                      ]





Author: Greg Herlihy <greghe@pacbell.net>
Date: Fri, 29 Jun 2007 00:35:21 CST
Raw View
On Jun 23, 9:54 am, nore...@this.is.invalid (Niels Dekker - no return
address) wrote:
> >> static_assert(false, "Do not instantiate this template!!!");
>
> >> IMO, a program should not be considered ill-formed, if this
> >> static_assert declaration is placed within a template that is
> >> not instantiated.
> Mathias Gaunard wrote:
> > Of course it is not ill-formed.
>
> I'm afraid that it *is* ill-formed, according to the current C++0x
> Draft.  (See below.)

No, the type-dependent BOOST_STATIC_ASSERT cannot be ill-formed before it is
instantiated. And a type-dependent template - as one would expect - may not
be instantiated until the template that it is dependent on - is
instantiated.

> > I think that kind of stuff is a lot used in boost, with their own
> > BOOST_STATIC_ASSERT emulation.
>
> The documentation of BOOST_STATIC_ASSERT warns against doing
> BOOST_STATIC_ASSERT(false).  Instead it suggests doing
> BOOST_STATIC_ASSERT(sizeof(T) == 0), within a template that should not
> be instantiated.http://www.boost.org/doc/html/boost_staticassert.html

Correct. Using a type-dependent condition ensures that the
BOOST_STATIC_ASSERT is not evaluated immediately - in the context of its
enclosing template's definition.

> But unfortunately both BOOST_STATIC_ASSERT calls appear to be
> ill-formed, even within an uninstantiated template, as Gennaro Prota
> explained to me (by e-mail).  Quoting the current Draft, 14.6, Name
> resolution [temp.res]:
>   "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."http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2284.pdf

The compiler does generate a valid specialization in this situation -
because if the "SpecializeMePlease" template definition were ill-formed,
then no specialization would have been generated and the
BOOST_STATIC_ASSERT would never have been evaluated. In other words, in
order for BOOST_STATIC_ASSERT(sizeof(T)==0) to be ill-formed, the
"SpecializeMePlease" specialization that led to its instantiation - must be
valid.

> And as Alberto Ganesh Barbati showed us that the expression sizeof(T)
> never evaluates to zero (by definition), doing
> BOOST_STATIC_ASSERT(sizeof(T) == 0) is ill-formed, just like
> BOOST_STATIC_ASSERT(false).

The two static asserts are evaluated in different contexts - the latter,
being non-dependent is evaluated in the context of the template definition;
while the former, being type-dependent, is evaluated in the context of a
specialization.

> So I guess the question is: is the Committee is willing to make an
> exception for static_assert, and allow its first argument to be false,
> within an uninstantiated template?

There is no exception needed. The language of the Standard is unambiguous:
the compiler must defer the resolution of a type-dependent expression until
the template has been specialized [   14.6/8]. But even without that rule, the
compiler has no alternative. Because even if the static assert evaluates to
false for every type T (which is not true, consider T=void which evaluates
to no value at all), the compiler still needs to identify the integer on the
left-hand side of the expression. After all, how could the compiler claim
that it had tested some number against zero for equality and yet not be able
specify exactly what that value (that did not compare equal to zero) was?

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                      ]





Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Fri, 29 Jun 2007 09:26:34 CST
Raw View
Greg Herlihy ha scritto:
> On Jun 23, 9:54 am, nore...@this.is.invalid (Niels Dekker - no return
> address) wrote:
>
>> And as Alberto Ganesh Barbati showed us that the expression sizeof(T)
>> never evaluates to zero (by definition), doing
>> BOOST_STATIC_ASSERT(sizeof(T) == 0) is ill-formed, just like
>> BOOST_STATIC_ASSERT(false).
>
> The two static asserts are evaluated in different contexts - the latter,
> being non-dependent is evaluated in the context of the template definition;
> while the former, being type-dependent, is evaluated in the context of a
> specialization.
>
>> So I guess the question is: is the Committee is willing to make an
>> exception for static_assert, and allow its first argument to be false,
>> within an uninstantiated template?
>
> There is no exception needed. The language of the Standard is unambiguous:
> the compiler must defer the resolution of a type-dependent expression until
> the template has been specialized [  14.6/8]. But even without that rule, the
> compiler has no alternative. Because even if the static assert evaluates to
> false for every type T (which is not true, consider T=void which evaluates
> to no value at all), the compiler still needs to identify the integer on the
> left-hand side of the expression. After all, how could the compiler claim
> that it had tested some number against zero for equality and yet not be able
> specify exactly what that value (that did not compare equal to zero) was?

It seems that my statement has been a source of confusion rather than
clarification. The reference I cited is about objects, not types. So,
it's not true that sizeof(T) > 0 for *every* type. It's true only for
*complete* types (those that can be instantiated to object). The
compiler cannot "optimize" the expression sizeof(T) == 0 assuming that
it always evaluates to false, because it might be ill-formed for some T
(for example: void). This is enough to force the compiler to treat the
expression as type-dependent.

Ganesh

---
[ 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                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Sun, 1 Jul 2007 14:22:21 GMT
Raw View
Niels Dekker - no return address ha scritto:
>   [ Thanks Greg, for revitalizing the discussion ]
>
> Alberto Ganesh Barbati wrote:
>> So it's not true that sizeof(T) > 0 for *every* type. It's true only
>> for *complete* types (those that can be instantiated to object).
>
> I hope you still agree that there is *no* type T, for which
> (sizeof(T)==0) evaluates to true...

Correct.

>> The compiler cannot "optimize" the expression sizeof(T) == 0 assuming that
>> it always evaluates to false, because it might be ill-formed for some T
>> (for example: void). This is enough to force the compiler to treat the
>> expression as type-dependent.
>
> Interesting.  Do you mean to say that if a program is ill-formed because
> of a static_assert(sizeof(T)==0, "") within an uninstantiated template,
> the compiler would not be allowed to say so?  If so, the program would
> be "ill-formed, no diagnostic /allowed/" !!!

No. The diagnostic is still required: the compiler should complain that
the sizeof operator is applied to an invalid type ([expr.sizeof] para
1). So the program is ill-formed in both cases, but reason of
ill-formedness is different: in order to provide the correct diagnostic
the compiler must treat the expression as type-dependent.

> BTW, I guess that by definition sizeof(T) > 0 is true for every
> *DefaultConstructible* type T.  So a C++0x compiler would be *allowed*
> to diagnose the following template definition, even without being
> instantiated:
>
>   #include <concepts>  // For the std::DefaultConstructible concept.
>
>   template<std::DefaultConstructible T>
>   void TemplateFunc(void) {
>     static_assert(sizeof(T)==0, "Ill-formed!");
>   }
>
> I would rather have the C++0x Standard stating explicitly that a static
> assert declaration has no effect within an uninstantiated template.

Hmm... I haven't fully grasped all the details of concepts, so I may be
wrong, but can't you declare a type to be DefaultConstructible before
providing a definition for such type? In that case you would have a
DefaultConstructible type which is still incomplete and therefore you
cannot apply sizeof() on it and we are still in the same situation as
above. I agree that's a corner case, however...

>   template<int> struct int_dependent_false {
>     enum { value = false }; };
>
>   template<const void*> struct ptr_dependent_false {
>     enum { value = false }; };
>
>   template<template<class> class> struct template_dependent_false {
>     enum { value = false }; };
>
> Unfortunately the list could go on and on, for each possible kind of
> template template argument:
>
>   template<template<class, class> class>
>   struct template_dependent_false2 {
>     enum { value = false }; };
>
>   template<template<class, class, class> class>
>   struct template_dependent_false3 {
>     enum { value = false }; };
>
> Is there a more "generic" technique to implement an "always false
> struct" for each kind of template argument?  Gennaro Prota and I
> recently had an e-mail discussion on this approach as well, but we
> couldn't think of an alternative...

These looks very much like tr1 type_traits to me... Those, together with
MPL techniques seem a very good alternative to me.

Ganesh

---
[ 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                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Thu, 21 Jun 2007 22:01:56 GMT
Raw View
Pedro Lamar=C3=A3o ha scritto:
> On Jun 19, 6:57 pm, nore...@this.is.invalid (Niels Dekker - no return
> address) wrote:
>=20
>>   ////////////////////////////////////////////////////////////
>>   template <typename T> void SpecializeMePlease(T) {
>>     static_assert( (sizeof(T) =3D=3D 0),
>>       "Do not instantiate this template");
>>   }
>=20
>> Would a compiler be allowed to reject the program, because it "knows"
>> that (sizeof(T) =3D=3D 0) is always false?
>=20
> A quick search in the current draft: neither [basic.types] nor
> [expr.sizeof] state explicitly that every sizeof() expression will
> result > 0.
>=20

It's a consequence of 1.8/5: "Unless it is a bit-field (9.6), a most
derived object shall have a non-zero size and shall occupy one or more
bytes of storage."

Ganesh

---
[ 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                      ]





Author: invalid@yahoo.com ("Genny [No Spam]")
Date: Sat, 23 Jun 2007 16:54:02 GMT
Raw View
Mathias Gaunard wrote:
> On 21 juin, 18:11, nore...@this.is.invalid (Niels Dekker - no return
> address) wrote:
>
>> I would like to be able to do something similar, using static_assert:
>>   static_assert(false, "Do not instantiate this template!!!");
>>
>> IMO, a program should not be considered ill-formed, if this
>> static_assert declaration is placed within a template that is not
>> instantiated.
>
> Of course it is not ill-formed.

Of course according to... ? According to the standard, 14.6 [temp.res]
par. 7:

     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.

Since, for some odd reason, I couldn't post to the newsgroup I wrote a
private mail to Niels, who pointed out that the boost docs for
BOOST_STATIC_ASSERT suggest using the sizeof( T ) == 0; that's wrong:
"tricking" the compiler into failing to provide a diagnostic means
explicitly asking for undefined behavior (it would be acceptable
*only* if the compiler explicitly documented that, as an extension, ...)

A quick search in the archives shows that I pointed out the error on
24 Jun 2004. That says something about Boost...

--
      \|||/                Gennaro Prota   -   For hire
      (o o)           https://sourceforge.net/projects/breeze/
--ooO-(_)-Ooo-----   (to mail: name . surname / yaho ! 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.comeaucomputing.com/csc/faq.html                      ]