On 12/6/19 7:15 AM, Soviet_Mario wrote:
> Il 06/12/19 04:39, James Kuyper ha scritto:
>> On 12/5/19 5:20 PM, Soviet_Mario wrote:
>>> since what version of standard, if any, an ENUM type can be
>>> an argument of a template ?
>>
>> It has always been possible to use an enumerated type as a template
>> parameter.
>
> sorry I'm not sure I have understood
>
> Do you mean to use it as just a VALUE (instancing it) in an
> generic integral parameter, or a proper TYPE-CHECKED
> declaration (so that giving non typed integer value while
> instancing would give a compile error) ?
Neither. I'm talking about a type, not a value. You, on the other hand,
were talking about a value, but referring to it as a type, which is
connected closely to the source of your confusion. I'll explain that in
more detail in my response to your later questions.
>> There is no special rule giving a enumerated type any
>> different status from any other type in that regard.
>
> Uhm ... ok, maybe I have outdated memories :\
I suspect it's not your memories that are the problem, but your
understanding of the issue.
>>> sth like
>>>
>>> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>>>
>>>
>>> template <RestrictedValues ttVal> class SizedField
>>
>> However, you're not using an enumerated type as a template argument,
>> you're using a enumeration value.
>
> Mmmm, exactly the point I am misunderstanding. I believed to
> have been able to establish a proper type-checking in that
> declaration.
There's nothing wrong with that declaration, as such. It just has
nothing to do with the contents of the sentence you started your message
with. What you refer to in that sentence would match the following code:
#include <vector>
std::vector<enum RestrictedValues> vrv;
The type "enum RestrictedValues" is allowed as an argument the the
std::vector template class, and that has always been allowed, for as
long as C++ (which wasn't known as C++ yet, at the time this feature was
added) has had templates.
Your code does NOT use a enumerated type as a template argument. It uses
a enumeration value as an argument. ttVall above is example of what is
called a template non-type argument. I believe that those were a
somewhat later addition to the language, but I also believe that they
were already fully supported before I first learned about C++, would
would have been in the late 1980s, well before the first version of the
C++ standard was approved.
The latest draft standard I have is n4659.pdf. Template non-type
arguments are described in section 17.3.2:
> If the type of a template-parameter contains a placeholder type (10.1.7.4, 17.1), the deduced parameter type is
> determined from the type of the template-argument by placeholder type deduction (10.1.7.4.1). If a deduced
> parameter type is not permitted for a template-parameter declaration (17.1), the program is ill-formed.
> A template-argument for a non-type template-parameter shall be a converted constant expression (8.20) of
> the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the
> value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
> (2.1) — a subobject (4.5),
> (2.2) — a temporary object (15.2),
> (2.3) — a string literal (5.13.5),
> (2.4) — the result of a typeid expression (8.2.8), or
> (2.5) — a predefined __func__ variable (11.4.1).
ttVall is type-checked. However, C++ allows the creation of values of
enumerated type that don't match any of the enumeration constants
associated with that type - see 10.2p8 for a precise specification of
the range of values permitted. Your template can therefore be
instantiated with any of those other values, which I suspect is not what
you want.
However, something that might work as you might like is to declare a
template class, but with no definition for that class. Provide explicit
specializations of the template for the particular values you want
supported, which don't use the generic definition. Then any use of the
template that doesn't match one of the specializations will produce an
error message. Here's some simplified example code:
#include <iostream>
enum mybool {FALSE, TRUE};
template <mybool val> struct boolname;
template <> struct boolname<FALSE> {
const char *name() const { return "False";};
};
template <> struct boolname<TRUE> {
const char *name() const { return "True";};
};
int main(void)
{
boolname<FALSE> t;
std::cout <<
t.name() << std::endl;
return 0;
}
If you change the final occurrence of FALSE in that code with
static_cast<mybool>(2), it will fail at compile time with a diagnostic,
because their is no specialization for that value, and no generic
definition of the template that could be used for unspecialized values.