Travis Vitek wrote:
Martin Sebor wrote:
Travis Vitek wrote:
Eric Lemings wrote:
Just a brief side note. I was just reviewing this test and
noticed that
pointers are not tested though they are valid scalar types
suitable for
use as integral_constant parameters. I think references
may be valid
parameters also.
I'm not sure.
The first thing that jumps to mind is that a pointer is not of
'integral' type. An enumeration isn't really an integral type either,
but they are implicitly convertible to one. Pointers aren't
convertible
to integral type without a cast.
According to temp.arg.nontype, a non-type, non-template template
parameter must be one of
-- an integral constant expression
-- the name of a non-type template-parameter
-- the address of an object or function with external linkage...
-- a constant expression that evaluates to a null pointer value
-- a constant expression that evaluates to a null member
pointer value
-- a pointer to member
So, yes, it is legal to use a pointer as a non-type template
parameter.
The issue I have is that the integral_constant<T,V> is supposed to
define an integral constant of type T with value V. Section
expr.const
says that a constant expression is an integral constant
expression if it
is of integral or enumeration type. An integral constant
expression can
be used as an array bound, a case expression, a bit field length,
enumeration initializer, static member initializer and as integral or
enumeration non-type template arguments.
I'm pretty sure you can't use a pointer value as an array bound, case
expression, bit field length or enumeration initializer, so
they aren't
really integral constants.
So I am sure you can instantiate std::integral_constant<void
(class_t::*)(), &class::method>, but I'm not sure if it
something that
should be tested.
If there's an implementation technique that would make the
instantiation ill-formed then I think it should be tested.
According to class.mem (p4) and class.static.data (p4) you aren't
allowed to initialize static members using a constant-initializer (i.e.
in the member declaration) if they are not of const integral or const
enumeration type. So the above instantiation on member pointer should be
prevented by the compiler. A quick test with msvc-8.0 and gcc-4.3 show
that this is the case.
Good point!
The following would be legal, but I'm already testing integral constants
for all integral types and an enum type, so I think I'm covered.
More important, though, the standard should specify the
requirements on the template arguments. If there are no
such requirements for something as fundamental as
integral_const, either in the latest working draft or
in one of the concepts papers (such as N2622), we should
at least bring it up on the list and/or open an issue to
have the spec clarified.
The standard does specify the requirements of the template arguments,
but only through association (to be an integral constant member, it has
to be a const static that is initialized with a constant-initializer,
Is this specified anywhere else besides the definition of the
class in [meta.help]? If not, I'm not sure that every detail
of a class definition shown in the spec qualifies as a normative
requirement.
and a constant initializer only works for enum and integral types). Is
this significant enough to warrant bringing up an issue?
IMO, the class should have an explicit requirement on the first
template argument. If there isn't one I would propose adding
paragraph 2 with the text:
-2- The template parameter T shall have an integral type (3.9.1).
integral_constant<T>::value shall be a integral constant
expression (5.19).
With concepts, we would change the definition of the class like
this (I think):
template <IntegralConstantExpressionType T, T v>
struct integral_constant {
// ...
};
Strangely, this isn't in N2625:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2625.pdf
Incidentally, it also seems to me that value should be declared
constexpr (both in our implementation and in the spec).
Travis