Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

enum type in template declaration

53 views
Skip to first unread message

Soviet_Mario

unread,
Dec 5, 2019, 5:21:05 PM12/5/19
to
since what version of standard, if any, an ENUM type can be
an argument of a template ?

sth like

enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };


template <RestrictedValues ttVal> class SizedField
{
private:
unsigned char zzArray [ttVal];


public:

etc etc

}


or if the syntax is wrong, how to workaround ?

The goal is to have a template depending on a restricted
well defined, and known at compile time, set of integral values







--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

James Kuyper

unread,
Dec 5, 2019, 10:40:01 PM12/5/19
to
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. There is no special rule giving a enumerated type any
different status from any other type in that regard.

> 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. That is a marginally newer feature of
C++, though I believe that it still pre-dates the first version of the
standard. There is no distinction for this purpose between values of
enumerated type and those of any other integer type.



Soviet_Mario

unread,
Dec 6, 2019, 7:15:40 AM12/6/19
to
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) ?

> 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 :\

>
>> 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.
How instead it should have been written ?
can you correct my example in order to non accept non
specific-enum integral instancing ?

> That is a marginally newer feature of
> C++, though I believe that it still pre-dates the first version of the
> standard. There is no distinction for this purpose between values of
> enumerated type and those of any other integer type.
>
>
>


Paavo Helde

unread,
Dec 6, 2019, 7:42:19 AM12/6/19
to
On 6.12.2019 14:15, 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

A template parameter can be a type, an int, etc. An enum type is also a
type:

enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };

template<typename T>
class A {
T member;
};

A<RestrictedValues> x; // OK

Here, an enum type is used as an argument of a template, as you requested.

However, I suspect that you actually want to use an enum value (not enum
type) as the template parameter - see below.

>
> Mmmm, exactly the point I am misunderstanding. I believed to have been
> able to establish a proper type-checking in that declaration.
> How instead it should have been written ?
> can you correct my example in order to non accept non specific-enum
> integral instancing ?

You have not said what your problem is. If you got a compiler error,
then what was the code and what was the error?

What you wrote was basically correct syntax (after commenting out "etc
etc"). This compiles fine:

enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };

template <RestrictedValues ttVal> class SizedField
{
private:
unsigned char zzArray[ttVal];


public:

//etc etc

};

int main() {
SizedField<B> foo;
}

Öö Tiib

unread,
Dec 6, 2019, 9:00:26 AM12/6/19
to
On Friday, 6 December 2019 14:15:40 UTC+2, Soviet_Mario wrote:
> Il 06/12/19 04:39, James Kuyper ha scritto:
> >
> > 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.
> How instead it should have been written ?
> can you correct my example in order to non accept non
> specific-enum integral instancing ?

We can easily help but right now your descriptions of problem are
too confusing to decipher (at least for me).
Please write compiling example (no pseudocodes) what you want to
achieve. What code compiles (or picks partial specialization that
you don't want it to pick) but you want it not to compile (or to pick
some other specialization).

James Kuyper

unread,
Dec 6, 2019, 9:56:45 AM12/6/19
to
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.

Manfred

unread,
Dec 6, 2019, 9:56:50 AM12/6/19
to
On 12/6/2019 1:15 PM, Soviet_Mario wrote:
>>> 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.
> How instead it should have been written ?
> can you correct my example in order to non accept non specific-enum
> integral instancing ?

As other have pointed out, it appears that what you want is a template
with a "non-type template parameter", the parameter being an enum value.

I did not check the standard, but it appears that this gives the type
checking you are looking for.
following up on the sample from Paavo:

> What you wrote was basically correct syntax (after commenting out "etc etc"). This compiles fine:
>
> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>
> template <RestrictedValues ttVal> class SizedField
> {
> private:
> unsigned char zzArray[ttVal];
>
>
> public:
>
> //etc etc
>
> };
>
> int main() {
> SizedField<B> foo;

SizedField<42> bar;

> }

This is what gcc reports:

$ c++ -std=c++17 -Wall templateArgEnum.cc
templateArgEnum.cc: In function ‘int main()’:
templateArgEnum.cc:22:16: error: invalid conversion from ‘int’ to
‘RestrictedValues’ [-fpermissive]
22 | SizedField<42> bar;
| ^
| |
| int
templateArgEnum.cc:21:17: warning: unused variable ‘foo’ [-Wunused-variable]
21 | SizedField<B> foo;
| ^~~
templateArgEnum.cc:22:18: warning: unused variable ‘bar’ [-Wunused-variable]
22 | SizedField<42> bar;
| ^~~

Soviet_Mario

unread,
Dec 6, 2019, 11:20:37 AM12/6/19
to
Il 06/12/19 13:42, Paavo Helde ha scritto:
> On 6.12.2019 14:15, 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
>
> A template parameter can be a type, an int, etc. An enum
> type is also a type:
>
> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>
> template<typename T>
> class A {
>   T member;
> };
>
> A<RestrictedValues> x; // OK
>
> Here, an enum type is used as an argument of a template, as
> you requested.
>
> However, I suspect that you actually want to use an enum
> value (not enum type) as the template parameter - see below.

none of both : I would like to declare that a parameter must
be of enum type, so that the values actually received by the
actual instance are not simply generic integral, but a
selected subset.

Assume you would like to model a "pixel" with a variable
depth of color, but that such depth should be checked (at
compile time) to be a power of two, and set up an enum like

enum EnumDepths { two = 2, four = 4, eight = 8 }

then the template should not take a simple integral
paramenter, as one could instantiate it wrongly

template <3> class ClsBMPofPixels;

so the typename must be of EnumDepths type, and only after
this compile time check, yes, then internally the VALUE
passed is used practically

>
>>
>> Mmmm, exactly the point I am misunderstanding. I believed
>> to have been
>> able to establish a proper type-checking in that declaration.
>> How instead it should have been written ?
>> can you correct my example in order to non accept non
>> specific-enum
>> integral instancing ?
>
> You have not said what your problem is. If you got a
> compiler error, then what was the code and what was the error ?

no, still just trying to figure out and think, not yet any
practical code

>
> What you wrote was basically correct syntax (after
> commenting out "etc etc"). This compiles fine:
>
> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>
> template <RestrictedValues ttVal> class SizedField
> {
> private:
>     unsigned char zzArray[ttVal];
>
>
> public:
>
>     //etc etc
>
> };
>
> int main() {
>     SizedField<B> foo;
> }
>

yes but would such code protect me from writing


template <5> class SizedField; ? Would the compiler check
that 5 is not a legal value of the enum ?

If so, okay ...


Oh, but BTW, what "helper" functions about run-time
INTROSPECTION are more or less standard ?


I've found some is_enum<EnumType> (), is_array<typename> ()
and so.

But a simple function like : bool is_of_type <typename> ()

in other languages such operators are named like "TypeOf"
(or typename, also a string representation could be usefull)

This question is for a concrete case.
I'm trying to build a 2D table container not particularly
generic : it supports just two type of contained items,
either double either a "fixed size string", but I'm not sure
I'd be able to write really generic functions as the two
basic types contain some equivalent operators, constructors
and comparison op, but also some semantically different
accessors for higher level function on a container.

So I'd appreciate some way a container could look inside
himself (at runtime) and be aware of its type and call
proper specialized functions where the syntax are not
equivalent and I cannot rely only on overload for automatic
selection of the best fit, or even in case I have to choose
to MIX data, thing that will end in ambiguity, as the two
types (fixedstrings and double) are largely convertible and
interchangeable, so a generic function with identical
signatures could not know what is the best to be called)

Soviet_Mario

unread,
Dec 6, 2019, 12:44:10 PM12/6/19
to
Il 05/12/19 23:20, Soviet_Mario ha scritto:
> since what version of standard, if any, an ENUM type can be
> an argument of a template ?
>
> sth like
>
> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>
>
> template <RestrictedValues ttVal> class SizedField
> {
> private:
> unsigned char zzArray [ttVal];
>
>
> public:
>
> etc etc
>
> }
>
>
> or if the syntax is wrong, how to workaround ?
>
> The goal is to have a template depending on a restricted
> well defined, and known at compile time, set of integral values
>
>
>
>
>
>
>
tnx for all for elucidations.
I still have some confused ideas about template instancing,
but I don't know exactly what to ask. So I make more
"experiments" before.
Ciao

Paavo Helde

unread,
Dec 6, 2019, 1:29:43 PM12/6/19
to
On 6.12.2019 18:20, Soviet_Mario wrote:
> Il 06/12/19 13:42, Paavo Helde ha scritto:
>>
>> What you wrote was basically correct syntax (after commenting out "etc
>> etc"). This compiles fine:
>>
>> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>>
>> template <RestrictedValues ttVal> class SizedField
>> {
>> private:
>> unsigned char zzArray[ttVal];
>>
>>
>> public:
>>
>> //etc etc
>>
>> };
>>
>> int main() {
>> SizedField<B> foo;
>> }
>>
>
> yes but would such code protect me from writing
>
>
> template <5> class SizedField; ? Would the compiler check that 5 is not
> a legal value of the enum ?

Yes, it will check. Why don't you try it out by yourself?

num RestrictedValues { A = 1, B = 2, C = 4, D = 8 };

template <RestrictedValues ttVal> class SizedField
{
private:
unsigned char zzArray[ttVal];


public:

//etc etc

};

int main() {
SizedField<3> foo;
}

1>main.cpp
1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): error C2440:
'specialization': cannot convert from 'int' to 'RestrictedValues'
1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): note:
Conversion to enumeration type requires an explicit cast (static_cast,
C-style cast or function-style cast)
1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): error C2973:
'SizedField': invalid template argument 'int'
1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(4): note: see
declaration of 'SizedField'

However, 'SizedField<RestrictedValues(3)> foo;' compiles. I would not
worry about that, in C++ one can always find ways to shoot himself.

>
> If so, okay ...
>
>
> Oh, but BTW, what "helper" functions about run-time INTROSPECTION are
> more or less standard ?
>
>
> I've found some is_enum<EnumType> (), is_array<typename> () and so.
>
> But a simple function like : bool is_of_type <typename> ()
>
> in other languages such operators are named like "TypeOf" (or typename,
> also a string representation could be usefull)

C++ is pretty statically typed, so you typically do not need things like
TypeOf to find out the type at run time. For polymorphic types there is
typeid() though which is similar, and also provides name() (which is not
guaranteed to be useful).

>
> This question is for a concrete case.
> I'm trying to build a 2D table container not particularly generic : it
> supports just two type of contained items, either double either a "fixed
> size string", but I'm not sure I'd be able to write really generic
> functions as the two basic types contain some equivalent operators,
> constructors and comparison op, but also some semantically different
> accessors for higher level function on a container.
>
> So I'd appreciate some way a container could look inside himself (at
> runtime) and be aware of its type and call proper specialized functions
> where the syntax are not equivalent and I cannot rely only on overload
> for automatic selection of the best fit, or even in case I have to
> choose to MIX data, thing that will end in ambiguity, as the two types
> (fixedstrings and double) are largely convertible and interchangeable,
> so a generic function with identical signatures could not know what is
> the best to be called)

You have to make up your mind if you have the type (double or string)
fixed at compile time or at run time. If at compile time, then there is
no need for the container to check the type at run time, as the type was
already fixed at the compile time and cannot change. E.g. a
std::vector<double> does not need to check at run-time if its elements
have suddenly turned into strings.

If the item type only becomes known only at run time, then it most
probably means you have some variant type. For this custom variant type
there are no overloaded functions present, you have to write them
yourself, and there you have to figure out the correct type at run-time
and act accordingly.

Soviet_Mario

unread,
Dec 6, 2019, 4:42:51 PM12/6/19
to
Il 06/12/19 19:29, Paavo Helde ha scritto:
> On 6.12.2019 18:20, Soviet_Mario wrote:
>> Il 06/12/19 13:42, Paavo Helde ha scritto:
>>>
TNX
(for the 1st part)

> However, 'SizedField<RestrictedValues(3)> foo;' compiles. I
> would not worry about that, in C++ one can always find ways
> to shoot himself.

ok, this kind of mistakes worries me less than simple slight
they will exist both, and interact from time to time (mutual
conversions, plus some calculations done in string mode,
like dates comparisons and some sorting in names/surnames
fields, and other in "double mode", statistics on data. The
two tables have to stay synced when one is sorted and the
other driven together)

> If at
> compile time, then there is no need for the container to
> check the type at run time, as the type was already fixed at
> the compile time and cannot change. E.g. a
> std::vector<double> does not need to check at run-time if
> its elements have suddenly turned into strings.

it is the template function that is generic and has to know
to cope with both in different semantically ways, or no ?

>
> If the item type only becomes known only at run time, then
> it most probably means you have some variant type.

uhm ... the allocation of proper types is known, but at
"CODE-TIME" some functions have duplexed code, and must know
which part to use according to the actual type of the
container caller.

Maybe this arises from bad design of the functions, dunno :(

anyway I'll study typeid and type_info keywords. Tnx

> For this
> custom variant type there are no overloaded functions
> present, you have to write them yourself, and there you have
> to figure out the correct type at run-time and act accordingly.
>


Paavo Helde

unread,
Dec 6, 2019, 5:51:46 PM12/6/19
to
On 6.12.2019 23:42, Soviet_Mario wrote:
>
> uhm ... the allocation of proper types is known, but at "CODE-TIME" some
> functions have duplexed code, and must know which part to use according
> to the actual type of the container caller.

Sorry, I cannot make heads or tails out of your babble, but as it seems
you are fascinated by templates and not really comprehending them, here
are some general remarks about them which might be helpful.

I know this can be confusing, but in C++ it is actually pretty simple:
templates are a compile-time feature. If you need something to be solved
by template mechanisms, it must be known at compile time. And vice
versa, if something is only known only at run-time, you have to do it in
an old-fashioned run-time way - an if, a switch, etc.

hth

saturn...@gmail.com

unread,
Dec 7, 2019, 4:54:13 AM12/7/19
to
在 2019年12月6日星期五 UTC+8上午6:21:05,Soviet_Mario写道:
> since what version of standard, if any, an ENUM type can be
> an argument of a template ?
>
> sth like
>
> enum class RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>
>
> template <RestrictedValues ttVal> class SizedField
> {
public:
static constexpr int aSize = static_cast<int>(ttVal);
> private:

> unsigned char zzArray [aSize];
>
>
> public:
>
> etc etc
>
> }
>
>
> or if the syntax is wrong, how to workaround ?
>
> The goal is to have a template depending on a restricted
> well defined, and known at compile time, set of integral values
>
>
>
> enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 };


template <RestrictedValues ttVal> class SizedField
{
private:
unsigned char zzArray [ttVal];


public:

etc etc

}
>
>
>
> --
> 1) Resistere, resistere, resistere.
> 2) Se tutti pagano le tasse, le tasse le pagano tutti
> Soviet_Mario - (aka Gatto_Vizzato)


If my modification fits your requirement?

Soviet_Mario

unread,
Dec 7, 2019, 12:54:31 PM12/7/19
to
Il 06/12/19 23:51, Paavo Helde ha scritto:
yes, in fact the template function which cannot solve one
aspect, has a switch.
But the control variable of the switch must be evaluated by
ITS TYPE (or some internal ID, hash or other info associated
to the type, not its value). In other words it must emulate
sort of a virtual function selector.

Many other aspect of the generic container using a lot of
common operators with a homogeneous semantic (assignments,
overloaded by both, comparisons, idem) are instead managed
by the container generically.

Indexing like an array but using operator () (row, column)
instead is semantically different for container<double> and
container<fixed_string>, the specialized versions do not
have even the same number of parameters, the latter has a
third parameter for index of character

I cannot explain well :\
anyway yes, there are lots of aspects of templates I miss to
understand


>
> hth

Soviet_Mario

unread,
Dec 7, 2019, 12:58:07 PM12/7/19
to
Il 07/12/19 10:53, saturn...@gmail.com ha scritto:
> 在 2019年12月6日星期五 UTC+8上午6:21:05,Soviet_Mario写道:
>> since what version of standard, if any, an ENUM type can be
>> an argument of a template ?
>>
>> sth like
>>
>> enum class RestrictedValues { A = 1, B = 2, C = 4, D = 8 };
>>
>>
>> template <RestrictedValues ttVal> class SizedField
>> {
> public:
> static constexpr int aSize = static_cast<int>(ttVal);
>> private:
>
>> unsigned char zzArray [aSize];


Yes it was a slight of mine to not have converted an enum to
int explicitely.
But the main question was not about that.
Anyway they have just reassured me that the compiler checks
for invalid non-forced cast in the reverse sense (from a
generic integer to the enum) in the specialization of an
instance. That was the source of my concern.

The forced manual cast did not worry me, I try not to shoot
in my foot :)
0 new messages