Topic: (Forward) declarations of enums
Author: "=?ISO-8859-1?Q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Sat, 15 Dec 2007 18:54:41 CST Raw View
On 15 Dez., 00:38, Francis Glassborow
<francis.glassbo...@btinternet.com> wrote:
> Sorry but I can see very little (if any) use for ctors for (strong)
> enums.
I agree with this.
> The only feature I would like to add to enums is the possibility
> of a user defined operator=.
Interesting, I hadn't expected this. Do you just mean the freedom
to define overloads of operator= (with e.g. std::string as 'insertion'
argument) or do you also mean the copy assignment operator?
And why do you see assignment preferable relative to construction
from?
Greetings from Bremen,
Daniel Kr gler
---
[ 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: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Sun, 16 Dec 2007 09:16:33 CST Raw View
Daniel Kr gler wrote:
> On 15 Dez., 00:38, Francis Glassborow
> <francis.glassbo...@btinternet.com> wrote:
>> Sorry but I can see very little (if any) use for ctors for (strong)
>> enums.
>
> I agree with this.
>
>> The only feature I would like to add to enums is the possibility
>> of a user defined operator=.
>
> Interesting, I hadn't expected this. Do you just mean the freedom
> to define overloads of operator= (with e.g. std::string as 'insertion'
> argument) or do you also mean the copy assignment operator?
> And why do you see assignment preferable relative to construction
> from?
>
I meant copy assignment (but other forms might be useful as well). As it
is at the moment it is rather difficult to range check enum evaluations.
For example:
enum example {examplemin =0, a, b, c, exampolemax = 26};
Now I can overload operator >> for std::istream so that the following
works (and the values are within range):
example foo(){
example x, y, z, sum;
std::cin >> x >> y >> z;
// but the following line does not support the range constraint:
sum = x + y + z;
..
Instead I have to meticulously overload every arithmetic operator for
both the first and the second and both arguments being of type example.
Of course if I never have (mutable) variables of type example ... Now
there is a thought, perhaps enums should have been immutable by default :-)
---
[ 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: brangdon@ntlworld.com (Dave Harris)
Date: Mon, 17 Dec 2007 18:11:40 GMT Raw View
lancediduck@nyc.rr.com (Lance Diduck) wrote (abridged):
> enums:
> [...]
> 3) should be able to have a user defined ctors, just like any other
> user defined type
Why? The purpose of a constructor is to set up the class invariant. I
don't see how an enum can have such an invariant.
-- Dave Harris, Nottingham, UK.
---
[ 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: Lance Diduck <lancediduck@nyc.rr.com>
Date: Thu, 6 Dec 2007 16:59:35 CST Raw View
On Dec 5, 6:02 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> >> Unfortunately, that is illegal in C++03. The rationale is that without
> >> the complete list of enumerators we can't determine the underlying type
> >> of E. The obvious workaround is to use an integral type instead of the
> >> enumeration and provide a hopefully clear comment:
>
> >> void Func(int); // actually a value of enum E should be passed here
>
> > The rationale has nothing to do with the underlying type of the enum -
> > and everything to do with the fact that source files fall into either
> > one of the two categories mentioned above: those that require the
> > complete enum definition and those that do not need the enum
> > definition at all. Because, unlike a class object, which can be passed
> > by reference or pointer (and thus may be an incomplete type) - an enum
> > is always referenced by value. So the practice of forwardly declaring
> > a class - simply has no equivalent purpose when it comes to enums.
>
> I disagree, the underlying type is the key point. If you know that, you
> can manipulate values of the enum even without any knowledge of what
> those values mean or how they have been obtained, as I've shown in the
> my first example. Indeed, there *is* a difference between class objects
> and enum, that is a declared (but not defined) class object is an
> incomplete type, while an enum will always be a complete type as soon as
> you know the underlying type. For this reason, it's unfair to compare
> enums with class objects, the correct comparison is between enums and
> *pointers* to class objects.
> Ganesh
enums:
1) should not be implictly convertible to any other enum or integral
type
2) should be able to have their type forward declarable, just like any
other user defined type
3) should be able to have a user defined ctors, just like any other
user defined type
In fact, it is possilbe (and sometimes useful) to use enums that have
no members at all. Consider
enum Color {};//one of 24 million values
Color c(12345);//OK
void foo(Color);//overloadable
But to forward declate enum types, that will eventually have members,
one can do this, and add a little more functionality to boot:
//enough of a definition to get you started
template<class EnumBase,class Storage>
struct EnumWrap:EnumBase{
typedef typename EnumBase::enum_type enum_type;
bool operator==(EnumWrap r)const{return r.m_val==m_val;}
bool operator==(enum_type r)const{return r==m_val;}
bool operator<(EnumWrap r)const{return m_val<r.m_val;}
bool operator<(enum_type r)const{return m_val<r.m_val;}
enum_type get()const{return m_val;}
EnumWrap():m_val(EnumBase::enum_default){}
EnumWrap(enum_type v):m_val(v){} //implict OK
explicit EnumWrap(Storage v):m_val(v){} //explict OK
//default copy ctor OK
private:
Storage m_val;
};
//plus a lot of helpful global compares, stream inserters, etc
struct EnumsHolder;
typedef EnumWrap<EnumsHolder,int> Enums;
void foo(Enums &);//fwd decl
Now, later, when we see the values, we can use them:
struct EnumsHolder{
enum SomeEnums{
Zero,One,Two,Three
};
typedef SomeEnums enum_type;
static enum_default enum_type enum_default=Zero;
};
void foo(Enums &d){
static Enums e=Enums::Two;
d=e;
}
and things like this
Enums f;
if (f==2)//will not compile
if (f==Enums::Two)//will compile
void g (int);
g(f);//will not compile
g(f.get());//OK
Lance
---
[ 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: "terminator(jam)" <farid.mehrabi@gmail.com>
Date: Sat, 8 Dec 2007 16:12:18 CST Raw View
On Dec 6, 12:05 am, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> On 5 Dez., 19:58, Greg Herlihy <gre...@mac.com> wrote:
>
> > I think that the more straightforward approach would be to limit the
> > number of source files that include the enum definition (or references
> > to it, including function prototypes). Only those source files that
> > need the enum definition (say, to pass as an argument in a function
> > call) should include the necessary header.
>
> This approach is fine and good, but I suppose that Alberto
> describes a system, where the usual techniques have
> been applied and that they can choose one of the following
> routes:
>
> - Switch to an indifferent (opaque), but unfortunately not
> typesafe integral type in the interface, that can hold the
> enum.
>
> - Stay typesafe using the enum but to the risk that you
> unnecessarily have to provide the enumerators all over
> the code.
>
> I think that Alberto's use-case happens much more often
> than one might expect. Usually there exist many functions,
> which only transfer the enum without the need to be aware
> of the enumerators it can hold. This would also apply to
> classes, like these:
>
> struct Something {
> enum State : unit64_t; // Would be fine
> State s; // Even this should work
>
> };
> > A forward-declaration of the enum E would be pointless - because
> > either a) a source file calls Func() (and therefore has to include the
> > complete definition of E anyway) or b) a source file does not call
> > Func() - in which case there is no reason to include either the Func()
> > function prototype or the forward declaration of E - in the first
> > place.
>
> I cannot agree here. Please note that there exists special rules,
> which allow a similar approach for classes. This is valid C++:
>
> struct S;
> void foo(S);
>
> This is for essentially the described need that often exists:
> A function declaration as a diffuse transfer capsule, which
> does not have to be aware of the struct definition.
>
> > The rationale has nothing to do with the underlying type of the enum -
> > and everything to do with the fact that source files fall into either
> > one of the two categories mentioned above: those that require the
> > complete enum definition and those that do not need the enum
> > definition at all. Because, unlike a class object, which can be passed
> > by reference or pointer (and thus may be an incomplete type) - an enum
> > is always referenced by value. So the practice of forwardly declaring
> > a class - simply has no equivalent purpose when it comes to enums.
>
> As shown above classes can also be provided as by-value
> arguments and do not need to be complete types at the
> point of function declaration.
>
> Actually I totally agree with Alberto, the new typed enums
> would be ideal candidates to support forward-declarable enum's.
> As far as I recall from earlier discussions on this theme, the
> current reason for *not* supporting forward-declarable enums
> is based on the conclusion that this would have the effect that
> pointers to enum's would need to be of the same size. This
> reason is lapsed given the current proposal to support enum's
> with specified underlying types. In contrast to classes, it
> would definitivly make sense to allow
>
> enum E : int;
the underlying type specifies the size of enum and IMHO should be
mentioned at definition site rather than the delaration site.I mean :
enum E;
void f(E);//what is the need to know the undelying type?
should compile just as the following does:
struct S;
void f(S);//no complaign about S not being defined.
in both cases the size and implementation of argument to ' f ' is
discovered at definition site rather than call site.
Moreover the syntax for underlying type specification can be discussed
I find the following more readable:
//declaration :
enum E;
//definition:
int enum E{/*define members*/};
regards,
FM.
---
[ 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: "terminator(jam)" <farid.mehrabi@gmail.com>
Date: Sat, 8 Dec 2007 16:12:31 CST Raw View
On Dec 7, 1:59 am, Lance Diduck <lancedid...@nyc.rr.com> wrote:
> On Dec 5, 6:02 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>
>
>
>
>
> > >> Unfortunately, that is illegal in C++03. The rationale is that without
> > >> the complete list of enumerators we can't determine the underlying type
> > >> of E. The obvious workaround is to use an integral type instead of the
> > >> enumeration and provide a hopefully clear comment:
>
> > >> void Func(int); // actually a value of enum E should be passed here
>
> > > The rationale has nothing to do with the underlying type of the enum -
> > > and everything to do with the fact that source files fall into either
> > > one of the two categories mentioned above: those that require the
> > > complete enum definition and those that do not need the enum
> > > definition at all. Because, unlike a class object, which can be passed
> > > by reference or pointer (and thus may be an incomplete type) - an enum
> > > is always referenced by value. So the practice of forwardly declaring
> > > a class - simply has no equivalent purpose when it comes to enums.
>
> > I disagree, the underlying type is the key point. If you know that, you
> > can manipulate values of the enum even without any knowledge of what
> > those values mean or how they have been obtained, as I've shown in the
> > my first example. Indeed, there *is* a difference between class objects
> > and enum, that is a declared (but not defined) class object is an
> > incomplete type, while an enum will always be a complete type as soon as
> > you know the underlying type. For this reason, it's unfair to compare
> > enums with class objects, the correct comparison is between enums and
> > *pointers* to class objects.
> > Ganesh
>
> enums:
> 1) should not be implictly convertible to any other enum or integral
> type
> 2) should be able to have their type forward declarable, just like any
> other user defined type
> 3) should be able to have a user defined ctors, just like any other
> user defined type
> In fact, it is possilbe (and sometimes useful) to use enums that have
> no members at all. Consider
> enum Color {};//one of 24 million values
> Color c(12345);//OK
> void foo(Color);//overloadable
>
> But to forward declate enum types, that will eventually have members,
> one can do this, and add a little more functionality to boot:
> //enough of a definition to get you started
> template<class EnumBase,class Storage>
> struct EnumWrap:EnumBase{
> typedef typename EnumBase::enum_type enum_type;
> bool operator==(EnumWrap r)const{return r.m_val==m_val;}
> bool operator==(enum_type r)const{return r==m_val;}
> bool operator<(EnumWrap r)const{return m_val<r.m_val;}
> bool operator<(enum_type r)const{return m_val<r.m_val;}
> enum_type get()const{return m_val;}
> EnumWrap():m_val(EnumBase::enum_default){}
> EnumWrap(enum_type v):m_val(v){} //implict OK
> explicit EnumWrap(Storage v):m_val(v){} //explict OK
> //default copy ctor OK
> private:
> Storage m_val;};
>
> //plus a lot of helpful global compares, stream inserters, etc
>
> struct EnumsHolder;
> typedef EnumWrap<EnumsHolder,int> Enums;
> void foo(Enums &);//fwd decl
>
> Now, later, when we see the values, we can use them:
> struct EnumsHolder{
> enum SomeEnums{
> Zero,One,Two,Three
> };
> typedef SomeEnums enum_type;
> static enum_default enum_type enum_default=Zero;};
>
did you ever think of this:
struct EnumsHolder{
enum enum_type{
Zero,One,Two,Three,
enum_default=Zero
};
};
> void foo(Enums &d){
> static Enums e=Enums::Two;
> d=e;
>
> }
>
> and things like this
> Enums f;
> if (f==2)//will not compile
> if (f==Enums::Two)//will compile
>
> void g (int);
> g(f);//will not compile
> g(f.get());//OK
>
fine tools, sorry I read it after my first post.
regards,
FM.
---
[ 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: jcoffin@taeus.com (Jerry Coffin)
Date: Sun, 9 Dec 2007 06:53:56 GMT Raw View
In article <7d6586c0-f260-4667-8a79-e1bd0a48e0c1
@e23g2000prf.googlegroups.com>, farid.mehrabi@gmail.com says...
> On Dec 6, 12:05 am, "Daniel Kr=FCgler" <daniel.krueg...@googlemail.com>
> wrote:
[ ... ]
> > enum E : int;
>=20
> the underlying type specifies the size of enum and IMHO should be
> mentioned at definition site rather than the delaration site.I mean :
>=20
> enum E;
> void f(E);//what is the need to know the undelying type?
Yes and no -- it's sufficient to declare a function taking that type as=20
a parameter, but the type needs to be complete by the time you include a=20
function call -- otherwise, the call won't compile.
The same is true here: you wouldn't need the underlying type just to=20
declare a function taking the enum, but you _would_ need it to generate=20
an actual call to the function.
> should compile just as the following does:
>=20
> struct S;
> void f(S);//no complaign about S not being defined.
Yes, as long as you never actually _call_ the function, this is=20
sufficient. By the time you call that function, however, you need a=20
definition of S in scope.
> in both cases the size and implementation of argument to ' f ' is
> discovered at definition site rather than call site.\
Not so. Consider attempting to call a function that's contained in a=20
library. Your compiler may never even see the definition of the function=20
being called. The information you've given it so far isn't enough for it=20
to generate a call to the function. For that, it needs to know the=20
actual type of the parameter. For example, on a 32-bit machine, you=20
might be able to generate either 4- or 8-byte enumerations. If so, the=20
compiler needs to know how many bytes to pass.
--=20
Later,
Jerry.
The universe is a figment of its own imagination.
---
[ 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: brangdon@ntlworld.com (Dave Harris)
Date: Sun, 9 Dec 2007 15:08:31 GMT Raw View
farid.mehrabi@gmail.com (terminator(jam)) wrote (abridged):
> the underlying type specifies the size of enum and IMHO should be
> mentioned at definition site rather than the delaration site.I mean
> :
>
> enum E;
> void f(E);//what is the need to know the undelying type?
>
> should compile just as the following does:
>
> struct S;
> void f(S);//no complaign about S not being defined.
>
> in both cases the size and implementation of argument to ' f ' is
> discovered at definition site rather than call site.
One issue concerns pointers and references. A pointer to a struct is
always a complete type even if the struct itself isn't. (This is
necessary for creating recursive data structures, which is what forward
references are really about. Enums have missed out historically because
they aren't recursive.)
On some hardware, a pointer to a char is bigger than a pointer to an int.
This means that in order to know the size of a pointer to an enum, we
have to know whether the enum is based on a char or an int. I imagine
that is what the current proposal is designed to do.
There are two alternatives. The first is to say that a pointer to an
incomplete enum is also incomplete. This might be surprising because it
differs from the rule for structs, and it might make incomplete enums
harder to work with, defeating the aim of supporting them in the first
place.
The second alternative is to say that pointers to enums have to be the
same size regardless of the range of the enum. In practice, that would
mean on platforms where the size of data pointers can differ, enums could
not be based on char. This could potentially be a breaking change in the
language. In practice such platforms are rare and probably don't use char
for enums anyway, but it's still a bit controversial.
Including the underlying size in the enum's declaration avoids the
problems of the other two alternatives. It doesn't seem to be very
onerous in practice.
-- Dave Harris, Nottingham, UK.
---
[ 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: Mon, 10 Dec 2007 07:15:35 GMT Raw View
[note to mods: this is a repost. A previous post did not appear after 3
days]
Lance Diduck ha scritto:
> >
> > enums:
> > 1) should not be implictly convertible to any other enum or integral
> > type
C++0X already introduces that concept in the form of /scoped/
enumerations. If you are not aware of that I suggest you read section
7.2 of the public draft of C++0X, paper N2461 that you can find at
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
> > 2) should be able to have their type forward declarable, just like any
> > other user defined type
That's exactly what I am proposing, as it's currently illegal.
> > 3) should be able to have a user defined ctors, just like any other
> > user defined type
I strongly disagree. There is no need for that and would make
enumerations a more complex entity than they are meant to be.
> > In fact, it is possilbe (and sometimes useful) to use enums that have
> > no members at all. Consider
> > enum Color {};//one of 24 million values
> > Color c(12345);//OK
> > void foo(Color);//overloadable
That's not what enumerations are meant for and is a bad programming
practice, IMHO. This use case would be better addressed by strong
typedefs as suggested by another poster in this thread.
> > But to forward declate enum types, that will eventually have members,
> > one can do this, and add a little more functionality to boot:
> > //enough of a definition to get you started
> > template<class EnumBase,class Storage>
> > struct EnumWrap:EnumBase{
You can't derive a struct from an enumeration!
> > typedef typename EnumBase::enum_type enum_type;
> > bool operator==(EnumWrap r)const{return r.m_val==m_val;}
> > bool operator==(enum_type r)const{return r==m_val;}
> > bool operator<(EnumWrap r)const{return m_val<r.m_val;}
> > bool operator<(enum_type r)const{return m_val<r.m_val;}
> > enum_type get()const{return m_val;}
> > EnumWrap():m_val(EnumBase::enum_default){}
> > EnumWrap(enum_type v):m_val(v){} //implict OK
> > explicit EnumWrap(Storage v):m_val(v){} //explict OK
> > //default copy ctor OK
> > private:
> > Storage m_val;
> > };
> > //plus a lot of helpful global compares, stream inserters, etc
The draft of C++0X already provides syntax to explicitly specify the
underlying type of an enum, namely:
enum E : int { /* ... */ };
or
enum class E : int { /* ... */ };
With my proposal, (forward) declaring the enum would simply be:
enum E : int;
or
enum class E : int;
In this framework, a library solution like yours would not be necessary,
as E itself would perform exactly the role that EnumWrap<E, int> is
supposed to provide and would do so in a much more natural, concise and
efficient way.
Regards,
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: Mon, 10 Dec 2007 07:32:22 GMT Raw View
Lance Diduck ha scritto:
>
> enums:
> 1) should not be implictly convertible to any other enum or integral
> type
C++0X already introduces that concept in the form of /scoped/
enumerations. If you are not aware of that I suggest you read section
7.2 of the public draft of C++0X, paper N2461 that you can find at
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
> 2) should be able to have their type forward declarable, just like any
> other user defined type
That's exactly what I am proposing, as it's currently illegal.
> 3) should be able to have a user defined ctors, just like any other
> user defined type
I strongly disagree. There is no need for that and would make
enumerations a more complex entity than they are meant to be.
> In fact, it is possilbe (and sometimes useful) to use enums that have
> no members at all. Consider
> enum Color {};//one of 24 million values
> Color c(12345);//OK
> void foo(Color);//overloadable
That's not what enumerations are meant for and is a bad programming
practice, IMHO. This use case would be better addressed by strong
typedefs as suggested by another poster in this thread.
> But to forward declate enum types, that will eventually have members,
> one can do this, and add a little more functionality to boot:
> //enough of a definition to get you started
> template<class EnumBase,class Storage>
> struct EnumWrap:EnumBase{
You can't derive a struct from an enumeration!
> typedef typename EnumBase::enum_type enum_type;
> bool operator==(EnumWrap r)const{return r.m_val==m_val;}
> bool operator==(enum_type r)const{return r==m_val;}
> bool operator<(EnumWrap r)const{return m_val<r.m_val;}
> bool operator<(enum_type r)const{return m_val<r.m_val;}
> enum_type get()const{return m_val;}
> EnumWrap():m_val(EnumBase::enum_default){}
> EnumWrap(enum_type v):m_val(v){} //implict OK
> explicit EnumWrap(Storage v):m_val(v){} //explict OK
> //default copy ctor OK
> private:
> Storage m_val;
> };
> //plus a lot of helpful global compares, stream inserters, etc
The draft of C++0X already provides syntax to explicitly specify the
underlying type of an enum, namely:
enum E : int { /* ... */ };
or
enum class E : int { /* ... */ };
With my proposal, (forward) declaring the enum would simply be:
enum E : int;
or
enum class E : int;
In this framework, a library solution like yours would not be necessary,
as E itself would perform exactly the role that EnumWrap<E, int> is
supposed to provide and would do so in a much more natural, concise and
efficient way.
Regards,
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: Mon, 10 Dec 2007 07:34:11 GMT Raw View
Dave Harris ha scritto:
>
> Including the underlying size in the enum's declaration avoids the
> problems of the other two alternatives. It doesn't seem to be very
> onerous in practice.
>
Please notice that syntax to specify size of the enum has already been
accepted and integrated in the current draft. My proposal is just about
allowing enums with "fixed" underlying type to be declared without also
declaring (thus defining) the list of enumerators.
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 Kanze <james.kanze@gmail.com>
Date: Mon, 10 Dec 2007 01:37:43 CST Raw View
On Dec 8, 11:12 pm, "terminator(jam)" <farid.mehr...@gmail.com> wrote:
> On Dec 6, 12:05 am, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
> wrote:
[...]
> > > A forward-declaration of the enum E would be pointless - because
> > > either a) a source file calls Func() (and therefore has to include the
> > > complete definition of E anyway) or b) a source file does not call
> > > Func() - in which case there is no reason to include either the Func()
> > > function prototype or the forward declaration of E - in the first
> > > place.
> > I cannot agree here. Please note that there exists special
> > rules, which allow a similar approach for classes. This is
> > valid C++:
> > struct S;
> > void foo(S);
I'm not sure that this is really as significant as the fact that
you can use S* and S& without the definition. The rule is, in
fact, that you can have a pointer or a reference to an
incomplete type. This doesn't work with enum's, so the standard
would need another type of incomplete type, which doesn't allow
pointers or references to it.
Alternatively, the forward declaration must specify the
underlying type. Or the standard requires the compiler to
worst-case it, and use a representation which would be
compatible with a void*. (I rather suspect that this would be
acceptable today, given the rarety of machines where pointers to
data can have different sizes. It wasn't in the distant past,
however, when enum was added to C.)
[...]
> > Actually I totally agree with Alberto, the new typed enums
> > would be ideal candidates to support forward-declarable enum's.
> > As far as I recall from earlier discussions on this theme, the
> > current reason for *not* supporting forward-declarable enums
> > is based on the conclusion that this would have the effect that
> > pointers to enum's would need to be of the same size. This
> > reason is lapsed given the current proposal to support enum's
> > with specified underlying types. In contrast to classes, it
> > would definitivly make sense to allow
> > enum E : int;
> the underlying type specifies the size of enum and IMHO should
> be mentioned at definition site rather than the delaration
> site.
That would perhaps seem logical, but it means that either E* and
E& are banned in such cases, or that you cannot have efficient
implementations of them on some architectures.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ 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: "terminator(jam)" <farid.mehrabi@gmail.com>
Date: Mon, 10 Dec 2007 01:36:33 CST Raw View
On Dec 7, 1:59 am, Lance Diduck <lancedid...@nyc.rr.com> wrote:
> On Dec 5, 6:02 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>
>
>
>
>
> > >> Unfortunately, that is illegal in C++03. The rationale is that without
> > >> the complete list of enumerators we can't determine the underlying type
> > >> of E. The obvious workaround is to use an integral type instead of the
> > >> enumeration and provide a hopefully clear comment:
>
> > >> void Func(int); // actually a value of enum E should be passed here
>
> > > The rationale has nothing to do with the underlying type of the enum -
> > > and everything to do with the fact that source files fall into either
> > > one of the two categories mentioned above: those that require the
> > > complete enum definition and those that do not need the enum
> > > definition at all. Because, unlike a class object, which can be passed
> > > by reference or pointer (and thus may be an incomplete type) - an enum
> > > is always referenced by value. So the practice of forwardly declaring
> > > a class - simply has no equivalent purpose when it comes to enums.
>
> > I disagree, the underlying type is the key point. If you know that, you
> > can manipulate values of the enum even without any knowledge of what
> > those values mean or how they have been obtained, as I've shown in the
> > my first example. Indeed, there *is* a difference between class objects
> > and enum, that is a declared (but not defined) class object is an
> > incomplete type, while an enum will always be a complete type as soon as
> > you know the underlying type. For this reason, it's unfair to compare
> > enums with class objects, the correct comparison is between enums and
> > *pointers* to class objects.
> > Ganesh
>
> enums:
> 1) should not be implictly convertible to any other enum or integral
> type
> 2) should be able to have their type forward declarable, just like any
> other user defined type
> 3) should be able to have a user defined ctors, just like any other
> user defined type
> In fact, it is possilbe (and sometimes useful) to use enums that have
> no members at all. Consider
> enum Color {};//one of 24 million values
> Color c(12345);//OK
> void foo(Color);//overloadable
>
> But to forward declate enum types, that will eventually have members,
> one can do this, and add a little more functionality to boot:
> //enough of a definition to get you started
> template<class EnumBase,class Storage>
> struct EnumWrap:EnumBase{
> typedef typename EnumBase::enum_type enum_type;
> bool operator==(EnumWrap r)const{return r.m_val==m_val;}
> bool operator==(enum_type r)const{return r==m_val;}
> bool operator<(EnumWrap r)const{return m_val<r.m_val;}
> bool operator<(enum_type r)const{return m_val<r.m_val;}
> enum_type get()const{return m_val;}
> EnumWrap():m_val(EnumBase::enum_default){}
> EnumWrap(enum_type v):m_val(v){} //implict OK
> explicit EnumWrap(Storage v):m_val(v){} //explict OK
> //default copy ctor OK
> private:
> Storage m_val;};
>
> //plus a lot of helpful global compares, stream inserters, etc
>
> struct EnumsHolder;
> typedef EnumWrap<EnumsHolder,int> Enums;
> void foo(Enums &);//fwd decl
>
> Now, later, when we see the values, we can use them:
> struct EnumsHolder{
> enum SomeEnums{
> Zero,One,Two,Three
> };
> typedef SomeEnums enum_type;
> static enum_default enum_type enum_default=Zero;};
>
why not just this:
struct EnumsHolder{
enum enum_type{
Zero,One,Two,Three,
enum_default=Zero
};
};
> void foo(Enums &d){
> static Enums e=Enums::Two;
> d=e;
>
> }
>
> and things like this
> Enums f;
> if (f==2)//will not compile
> if (f==Enums::Two)//will compile
>
> void g (int);
> g(f);//will not compile
> g(f.get());//OK
>
> Lance
>
> ---
fine tools, sorry I read it after my first post.
regards,
FM.
---
[ 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, 11 Dec 2007 07:26:40 GMT Raw View
Alberto Ganesh Barbati ha scritto:
>=20
> Has this issue been discussed before? Could it be considered? Is there
> something that I'm missing?
>=20
Very good, it's clear from some answers that this issue wasn't discussed
before and it's worth considering, so I am seeking help from language
lawyers in order to prepare a formal proposal. I have already identified
a few places that needs changes:
In [basic.def]/2, where it says
"A declaration is a definition unless [long list of cases]."
the [long list of cases] shall include "[unless] it declares an
enumeration without specifying a list of enumerators (7.2)".
In [dcl.type.elab]/1, where it says:
"If an elaborated-type-specifier is the sole constituent of a
declaration, the declaration is ill-formed unless [...] it
has one of the following forms:"
class-key identifier ;
friend class-key ::opt identifier ;
friend class-key ::opt simple-template-id ;
friend class-key ::opt nested-name-specifier identifier ;
friend class-key ::opt nested-name-specifier template opt
simple-template-id ;"
Add to the list of allowed forms the two cases:
enum struct identifier ;
enum class identifier ;
Rationale: scoped enumerations always have fixed underlying type (it's
int if not explicitly specified) so it should be possible to declare
them even without the enum-base term.
[dcl.enum]/1 In the grammar, replace:
enum-specifier:
enum-key identifier opt enum-base opt { enumerator-list opt }
enum-key identifier opt enum-base opt { enumerator-list , }
with:
enum-specifier:
enum-key identifier opt enum-base opt enum-body opt
enum-key nested-name-specifier enum-body
enum-body:
{ enumerator-list opt }
{ enumerator-list , }
Rationale: the first rule is the key addition as it allows omitting
the list of enumerators. The last rule is needed so that an enumeration
declared in a nested scope can be defined in an enclosing scope.
Add the following sentence (compare wording with [dcl.type.elab]/1):
"If the enum-body is not present, the declaration is ill-formed unless
it has one of the following forms:
enum identifier enum-base ;
enum class identifier enum-base opt ;
enum struct identifier enum-base opt ;
[Note: in this case the declaration is not a definition and the
underlying type of the declared enumeration is always fixed
-end note]"
Rationale: this to explicitly lists the allowed forms of "forward"
declaration and at the same time to disallow declarations like:
enum A : int a;
that may be difficult to parse for both machines and humans.
Add a new paragraph (the wording is taken almost verbatim from [class]/10=
):
"If the enum-key is followed by a nested-name-specifier, the
enum-specifier shall refer to an enumeration that was previously
declared directly in the class or namespace to which the
nested-name-specifier refers (i.e., neither inherited nor introduced
by a using-declaration), and the enum-specifier shall appear in a
namespace enclosing the previous declaration."
Only one thing is now missing, and I guess it's going to be most
controversial point: what about redeclarations? Before considering
alternatives, it may be interesting to consider the following statement
in [dcl.type.elab]/3:
"The enum-key used in an elaborated-type-specifier need not match the
one in the enumeration=E2=80=99s definition [ Example:
enum class E { a, b };
enum E x =3D E::a; // OK
=E2=80=94end example ]"
Well, this statement sounds a bit fishy to me. I agree that the example
"looks" correct, but this one:
enum E { a, b };
enum class E x =3D a; // also OK with current wording
doesn't look correct at all to me. My opinion is that it was a mistake
to replace enum with enum-key in the definition of
elaborated-type-specifier (C++03 used enum, it was replaced with
enum-key in the draft). In any case, the sentence needs amending, as
with this proposal an elaborated-type-specifier can refer to an
enumeration that has been declared but not yet defined. My suggestion is
get back to the C++03 definition of elaborated-type-specifier and drop
the fishy statement.
Back to the redeclaration issue, we have two quasi-orthogonal things to
consider:
1) the enum-key, we have only two alternatives:
1a) The enum-key in a redeclaration of a previously declared
enumeration shall match the first declaration.
1b) The enum-key in a redeclaration of a previously declared
enumeration need not match the previous declaration.
2) the underlying type, we also have two alternatives:
2a) A redeclaration of a previously declared enumeration shall not
specify an enum-base, the underlying type is the one determined by the
first declaration.
2b) Two declarations of the same enumeration shall specify, either
implicitly or explicitly, the same underlying type.
While I have a strong preference for 1a) over 1b) (the reason is similar
to the one I exposed about the "fishy" statement), the choice between 2a
and 2b is not so obvious. I believe 2b) is superior because 2a) has two
problems:
First problem:
--- a.h
enum E : int;
void fa(E);
--- b.h
enum E : int;
void fb(E);
--- c.cpp
#include "a.h"
#include "b.h" // ill-formed: re-declaration of underlying type of E
Second problem:
--- e.h
enum class E { a, b, c }; // notice: enum class -> type is int
--- a.cpp
#include "e.h"
static_assert(sizeof(E) =3D=3D sizeof(int));
--- b.cpp
enum class E : short;
#include "e.h" // violation of ODR here!
static_assert(sizeof(E) =3D=3D sizeof(short));
However, 2b makes the definition syntax a bit redundant:
enum E : int;
enum E : int { a, b, c }; // the ": int" is required, ugh!
but it's a small price to pay, IMHO. So in the end, the statement about
redeclaration may sound like:
"Two declarations of the same enumeration shall have matching
enum-keys and shall specify, either implicitly or explicitly, the same
underlying type."
(the "either implicitly or explicitly" refers to the fact that a scoped
enumeration without an explicit enum-base has implicitly int as the
underlying type.)
I think that should be enough.
Any feedback is appreciated.
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: Tringi@mx-3.cz (=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=)
Date: Tue, 11 Dec 2007 17:13:25 GMT Raw View
Dne Tue, 11 Dec 2007 08:26:40 +0100 Alberto Ganesh Barbati =20
<AlbertoBarbati@libero.it> napsal/-a:
> Alberto Ganesh Barbati ha scritto:
>
> [...]
>
> Any feedback is appreciated.
>
Let me just say that I believe that this little feature you described is =
=20
really worth considering.
At least for consistency, when most of the names can be forward-declared =
=20
today in C++.
I have otherwise no technical objection agains your proposal.
>
> Ganesh
>
PS: I would also be happy if "namespace xyz;" was allowed, just for =20
homogenity ;)
--=20
Jan Ringo=B9, Tringi@MX-3.cz
http://Tringi.MX-3.cz
http://www.ringos.cz
---
[ 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, 11 Dec 2007 21:39:26 GMT Raw View
Alberto Ganesh Barbati ha scritto:
> Very good, it's clear from some answers that this issue wasn't discusse=
d
> before and it's worth considering, so I am seeking help from language
> lawyers in order to prepare a formal proposal. I have already identifie=
d
> a few places that needs changes:
It doesn't matter how long you think about it, as soon as you read back
what you have written, some more (possibly better) ideas come out.
First of all, let me formalize a change to [dcl.type.elab] that I just
sketched in my previous post:
[dcl.type.elab]: In the definition of elaborated-type-specifier:
elaborated-type-specifier:
class-key ::opt nested-name-specifier opt identifier
class-key ::opt nested-name-specifier opt template opt
simple-template-id
enum-key ::opt nested-name-specifieropt identifier
replace the non-terminal enum-key with the keyword enum (this would mean
reverting to the C++03 defintion).
Rationale: in my opinion, allowing "enum class E" or "enum struct E" as
elaborated type specifiers isn't actually that important, especially
when they both can be spelled equivalently as "enum E" as the draft
already suggests (see below). Anyway, elaborated type specifiers are
actually rarely used in C++, given that E and enum E both refer to the
same type in 99% of the cases, so we won't miss much.
This change has a few repercussions:
> In [dcl.type.elab]/1, where it says:
>=20
> "If an elaborated-type-specifier is the sole constituent of a
> declaration, the declaration is ill-formed unless [...] it
> has one of the following forms:"
> class-key identifier ;
> friend class-key ::opt identifier ;
> friend class-key ::opt simple-template-id ;
> friend class-key ::opt nested-name-specifier identifier ;
> friend class-key ::opt nested-name-specifier template opt
> simple-template-id ;"
>=20
> Add to the list of allowed forms the two cases:
>=20
> enum struct identifier ;
> enum class identifier ;
>=20
Given that "enum struct identifier" and "enum class identifier" are no
longer elaborated-type-specifiers, the two cases can no longer be added.
Actually there's no need for those, as those cases are already listed in
the proposed changes to [dcl.enum]/1.
> [...] it may be interesting to consider the following statement
> in [dcl.type.elab]/3:
>=20
> "The enum-key used in an elaborated-type-specifier need not match the
> one in the enumeration=E2=80=99s definition [ Example:
>=20
> enum class E { a, b };
> enum E x =3D E::a; // OK
>=20
> =E2=80=94end example ]"
>=20
> Well, this statement sounds a bit fishy to me. I agree that the example
> "looks" correct, but this one:
>=20
> enum E { a, b };
> enum class E x =3D a; // also OK with current wording
>=20
> doesn't look correct at all to me. My opinion is that it was a mistake
> to replace enum with enum-key in the definition of
> elaborated-type-specifier (C++03 used enum, it was replaced with
> enum-key in the draft). In any case, the sentence needs amending, as
> with this proposal an elaborated-type-specifier can refer to an
> enumeration that has been declared but not yet defined. My suggestion i=
s
> get back to the C++03 definition of elaborated-type-specifier and drop
> the fishy statement.
If "enum class E" is no longer an elaborated-type-specifier, my
objection no longer holds. Indeed the "fishy" statement is somehow
necessary, because otherwise we could no longer have an
elaborated-type-specifier referring to "enum class E". Moreover, the
entire paragraph 3 needs to be reverted to the C++03 version in order to
get rid of the enum-key. In the end, I propose replacing paragraph 3:
"The class-key or enum-key present in the elaborated-type-specifier
shall agree in kind with the declaration to which the name in the
elaborated-type-specifier refers. [...] Thus, in any
elaborated-type-specifier, the enum-key shall be used to refer to an
enumeration (7.2), [...] The enum-key used in an
elaborated-type-specifier need not match the one in the enumeration=E2=80=
=99s
definition."
with:
"The class-key or enum keyword present in the
elaborated-type-specifier shall agree in kind with the declaration
to which the name in the elaborated-type-specifier refers. [...] Thus,
in any elaborated-type-specifier, the enum keyword shall be used to
refer to an enumeration (7.2) regardless of the enum-key used to
declare it, [...]"
>=20
> 2) the underlying type, we also have two alternatives:
>=20
> 2a) A redeclaration of a previously declared enumeration shall not
> specify an enum-base, the underlying type is the one determined by the
> first declaration.
This reminds me the behaviour of default arguments; compare with
[dcl.fct.default]/4: "A default argument shall not be redefined by a
later declaration (not even to the same value)." Maybe this approach is
not as bad as I depicted it in my previous post.
>=20
> 2b) Two declarations of the same enumeration shall specify, either
> implicitly or explicitly, the same underlying type.
There is one third alternative, in the middle between the two:
2c) A redeclaration of a previously declared enumeration shall either
have no enum-base or have an enum-base specifying the same type
as the underlying type of the first declaration. In the former case,
the underlying type remains the one determined by the first
declaration.
For cases 2a) and 2c) we would need to add in [basic.def.odr]/5, to the
list of ODR requirements, the following:
- If D is an enumeration with fixed underlying type, the underlying
type is the same in every translation unit.
This is necessary, because in the following:
--- fileB.cpp
enum E : int;
enum E { a, b };
--- fileB.cpp
enum E : short;
enum E { a, b };
the requirement "each definition of D shall consist of the same sequence
of tokens" is satisfied, yet the two underlying types differ.
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: Lance Diduck <lancediduck@nyc.rr.com>
Date: Fri, 14 Dec 2007 14:37:24 CST Raw View
On Dec 10, 2:15 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> [note to mods: this is a repost. A previous post did not appear after 3
> days]
>
> Lance Diduck ha scritto:
> > > enums:
> > > 1) should not be implictly convertible to any other enum or integral
> > > type
>
> C++0X already introduces that concept in the form of /scoped/
> enumerations. If you are not aware of that I suggest you read section
> 7.2 of the public draft of C++0X, paper N2461 that you can find athttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
Yes thank, I have read similar proposals. It woud be a great addition
to the language, so we will not have to bother making wrapper classes
in the future to achive the same result.
>
> > > 2) should be able to have their type forward declarable, just like any
> > > other user defined type
>
> That's exactly what I am proposing, as it's currently illegal.
I hope it gets voted in
>
> > > 3) should be able to have a user defined ctors, just like any other
> > > user defined type
>
> I strongly disagree. There is no need for that and would make
> enumerations a more complex entity than they are meant to be.
I can already overload operators for them, and C++TPL give examples of
a operator++ for enums. I routinely overload operator<<(std::ostream
&,Enum) form mine for the obvious reasons.
I dont understand how giving enums ctors complicates anything. It
would be very similar to the semantics of union ctors and dtors.
> > > In fact, it is possilbe (and sometimes useful) to use enums that have
> > > no members at all. Consider
> > > enum Color {};//one of 24 million values
> > > Color c(12345);//OK
> > > void foo(Color);//overloadable
>
> That's not what enumerations are meant for and is a bad programming
> practice, IMHO. This use case would be better addressed by strong
> typedefs as suggested by another poster in this thread.
Again, we dont have strong typedefs, and will be years before we see
this in compilers.
Just because a particular C++ implementation device (namely enums) is
used in a way that is not customary, well, does not make it bad. If
every new and novel technique were "bad programming practice" we would
never have had template metaprogramming, generic programming, policy
classes, multiple inheritance, and so forth.
Other than "this is not how enums are normally used" what is wrong
with it??
> > > But to forward declate enum types, that will eventually have members,
> > > one can do this, and add a little more functionality to boot:
> > > //enough of a definition to get you started
> > > template<class EnumBase,class Storage>
> > > struct EnumWrap:EnumBase{
>
> You can't derive a struct from an enumeration!
You are right. But I am not inheriting form an enum anywhere
> The draft of C++0X already provides syntax to explicitly specify the
> underlying type of an enum, namely:
>
> enum E : int { /* ... */ };
>
> or
>
> enum class E : int { /* ... */ };
>
Yes, and when the compilers are generally available that supports this
then my wrapper class will not be as useful.
Lance
---
[ 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: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Fri, 14 Dec 2007 17:38:20 CST Raw View
Lance Diduck wrote:
>
>>>> 3) should be able to have a user defined ctors, just like any other
>>>> user defined type
>> I strongly disagree. There is no need for that and would make
>> enumerations a more complex entity than they are meant to be.
> I can already overload operators for them, and C++TPL give examples of
> a operator++ for enums. I routinely overload operator<<(std::ostream
> &,Enum) form mine for the obvious reasons.
> I dont understand how giving enums ctors complicates anything. It
> would be very similar to the semantics of union ctors and dtors.
Sorry but I can see very little (if any) use for ctors for (strong)
enums. The only feature I would like to add to enums is the possibility
of a user defined operator=.
---
[ 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: Sat, 15 Dec 2007 15:11:28 GMT Raw View
Francis Glassborow ha scritto:
> Lance Diduck wrote:
>
>>
>>>>> 3) should be able to have a user defined ctors, just like any other
>>>>> user defined type
>>> I strongly disagree. There is no need for that and would make
>>> enumerations a more complex entity than they are meant to be.
>> I can already overload operators for them, and C++TPL give examples of
>> a operator++ for enums. I routinely overload operator<<(std::ostream
>> &,Enum) form mine for the obvious reasons.
>> I dont understand how giving enums ctors complicates anything. It
>> would be very similar to the semantics of union ctors and dtors.
>
>
> Sorry but I can see very little (if any) use for ctors for (strong)
> enums. The only feature I would like to add to enums is the possibility
> of a user defined operator=.
>
You can easily emulate that (and constructors too), by wrapping the enum
inside a struct, for example:
struct E
{
enum EDetail : int
{
/* enumerators */
};
// constructors
constexpr E() : e(default-value-here) {}
explicit constexpr E(int x) : e(x) {}
// conversion operators
explicit constexpr operator int() { return e; }
// other stuff
E& operator=(whatever);
private:
EDetail e;
};
HTH,
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: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Sat, 15 Dec 2007 10:58:57 CST Raw View
Lance Diduck ha scritto:
> On Dec 10, 2:15 am, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>> Lance Diduck ha scritto:
>>>> 3) should be able to have a user defined ctors, just like any other
>>>> user defined type
>> I strongly disagree. There is no need for that and would make
>> enumerations a more complex entity than they are meant to be.
> I can already overload operators for them, and C++TPL give examples of
> a operator++ for enums. I routinely overload operator<<(std::ostream
> &,Enum) form mine for the obvious reasons.
> I dont understand how giving enums ctors complicates anything. It
> would be very similar to the semantics of union ctors and dtors.
An enumeration is a scalar type and that implies it is also a trivial
type (3.9/9). A trivial class type must have a trivial default
constructor (9/5), this means that:
1) if you define a default constructor, the class type is no longer trivial.
2) if you define any non-default constructor, you must use the "=
default" syntax to declare the default constructor trivial.
I'm not saying that it can't be done, but if you want to provide wording
to add constructors to enumeration, you've got to be extra careful in
order to avoid the oxymoron of a scalar type that is not trivial. Such a
wording would necessarily negate the possibility to have a non-trivial
default constructor. Now, having a default constructor was probably the
only interesting thing, IMHO. Without the default constructor the
feature completely lose its appeal, as non-default constructors can
easily be emulated with free functions:
enum class E
{
E(ParamType x);
/* list of enumerators */
};
can be written:
enum class E
{
/* list of enumerators */
};
E MakeE(ParamType x);
Regards,
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, 4 Dec 2007 23:31:11 GMT Raw View
Hi Everybody,
in a project I am working on, we have an enumeration with several
hundred enumerators that is generated by an automatic tool. Each
enumerator represent an ID of localizable string. The localizer
component is accessible from several places on in the project, however,
only very few compilation units actually require access to the values of
the enumerators. Each time the automatic tool re-generate the
enumeration, nearly half of the project have to be re-compiled, although
only few compilation units would actually need it. A way to isolate the
enumerators while keeping the type-safety provided by the enumerated
type would be very useful.
The first thing that comes in mind is to "forward" declare the
enumeration (that is to declare the name of the enumeration without
listing all enumerators), like this:
enum E; // enumerators defined elsewhere: illegal in C++03
void Func(E);
Unfortunately, that is illegal in C++03. The rationale is that without
the complete list of enumerators we can't determine the underlying type
of E. The obvious workaround is to use an integral type instead of the
enumeration and provide a hopefully clear comment:
void Func(int); // actually a value of enum E should be passed here
but we lose type-safety and the possibility to use the enum for
overloading, not considering that there will always be someone who won't
read the comment.
In C++0X a new syntax for enumerations is being introduced that allows
the underlying type to be specified, like this:
enum E : int // underlying type is int
{
// enumerators here
};
Now, once the underlying type is specified with this syntax, do we
actually need the enumerators to be able to use the type? I mean, what
problems could there be in the following:
enum E : int; // enumerators defined elsewhere: illegal in C++0X
void Func(E); // it's an E but it's passed as an int
Actually, once we know the underlying type, the enumeration is (nearly)
a complete type! So we might even think about writing:
enum E : int; // enumerators defined elsewhere: illegal in C++0X
E e; // sizeof(e) == sizeof(int)
However, if interpret correctly the current draft (paper N2461 at the
moment of writing) any enum declaration must have an enumerator list
enclosed in braces even if the underlying type is specified.
Am I interpreting the draft correctly?
I believe that declaring an enumeration without the list of enumerator
should be allowed in case the underlying type is specified. It should be
given the same semantic as a declaration of a struct, in the sense that
you can declare the enumeration any number of times provided that 1) all
declarations use the same enum-key and underlying type, 2) at most one
has a list of enumerators. The only difference from structs is that even
if the list of enumerators is omitted, the type is actually complete.
Has this issue been discussed before? Could it be considered? Is there
something that I'm missing?
Thanks in advance,
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: Greg Herlihy <greghe@mac.com>
Date: Wed, 5 Dec 2007 12:58:50 CST Raw View
On Dec 4, 3:31 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
wrote:
> Hi Everybody,
>
> in a project I am working on, we have an enumeration with several
> hundred enumerators that is generated by an automatic tool. Each
> enumerator represent an ID of localizable string. The localizer
> component is accessible from several places on in the project, however,
> only very few compilation units actually require access to the values of
> the enumerators. Each time the automatic tool re-generate the
> enumeration, nearly half of the project have to be re-compiled, although
> only few compilation units would actually need it. A way to isolate the
> enumerators while keeping the type-safety provided by the enumerated
> type would be very useful.
I think that the more straightforward approach would be to limit the
number of source files that include the enum definition (or references
to it, including function prototypes). Only those source files that
need the enum definition (say, to pass as an argument in a function
call) should include the necessary header.
> The first thing that comes in mind is to "forward" declare the
> enumeration (that is to declare the name of the enumeration without
> listing all enumerators), like this:
>
> enum E; // enumerators defined elsewhere: illegal in C++03
> void Func(E);
A forward-declaration of the enum E would be pointless - because
either a) a source file calls Func() (and therefore has to include the
complete definition of E anyway) or b) a source file does not call
Func() - in which case there is no reason to include either the Func()
function prototype or the forward declaration of E - in the first
place.
> Unfortunately, that is illegal in C++03. The rationale is that without
> the complete list of enumerators we can't determine the underlying type
> of E. The obvious workaround is to use an integral type instead of the
> enumeration and provide a hopefully clear comment:
>
> void Func(int); // actually a value of enum E should be passed here
The rationale has nothing to do with the underlying type of the enum -
and everything to do with the fact that source files fall into either
one of the two categories mentioned above: those that require the
complete enum definition and those that do not need the enum
definition at all. Because, unlike a class object, which can be passed
by reference or pointer (and thus may be an incomplete type) - an enum
is always referenced by value. So the practice of forwardly declaring
a class - simply has no equivalent purpose when it comes to enums.
> I believe that declaring an enumeration without the list of enumerator
> should be allowed in case the underlying type is specified. It should be
> given the same semantic as a declaration of a struct, in the sense that
> you can declare the enumeration any number of times provided that 1) all
> declarations use the same enum-key and underlying type, 2) at most one
> has a list of enumerators. The only difference from structs is that even
> if the list of enumerators is omitted, the type is actually complete.
>
> Has this issue been discussed before? Could it be considered? Is there
> something that I'm missing?
You are describing "strong" or "opaque" typedefs. See:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1891.pdf
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2141.html
I am not sure whether strong typedefs will make it into C++ or not.
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: "=?ISO-8859-1?Q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Wed, 5 Dec 2007 15:05:01 CST Raw View
On 5 Dez., 19:58, Greg Herlihy <gre...@mac.com> wrote:
> I think that the more straightforward approach would be to limit the
> number of source files that include the enum definition (or references
> to it, including function prototypes). Only those source files that
> need the enum definition (say, to pass as an argument in a function
> call) should include the necessary header.
This approach is fine and good, but I suppose that Alberto
describes a system, where the usual techniques have
been applied and that they can choose one of the following
routes:
- Switch to an indifferent (opaque), but unfortunately not
typesafe integral type in the interface, that can hold the
enum.
- Stay typesafe using the enum but to the risk that you
unnecessarily have to provide the enumerators all over
the code.
I think that Alberto's use-case happens much more often
than one might expect. Usually there exist many functions,
which only transfer the enum without the need to be aware
of the enumerators it can hold. This would also apply to
classes, like these:
struct Something {
enum State : unit64_t; // Would be fine
State s; // Even this should work
};
> A forward-declaration of the enum E would be pointless - because
> either a) a source file calls Func() (and therefore has to include the
> complete definition of E anyway) or b) a source file does not call
> Func() - in which case there is no reason to include either the Func()
> function prototype or the forward declaration of E - in the first
> place.
I cannot agree here. Please note that there exists special rules,
which allow a similar approach for classes. This is valid C++:
struct S;
void foo(S);
This is for essentially the described need that often exists:
A function declaration as a diffuse transfer capsule, which
does not have to be aware of the struct definition.
> The rationale has nothing to do with the underlying type of the enum -
> and everything to do with the fact that source files fall into either
> one of the two categories mentioned above: those that require the
> complete enum definition and those that do not need the enum
> definition at all. Because, unlike a class object, which can be passed
> by reference or pointer (and thus may be an incomplete type) - an enum
> is always referenced by value. So the practice of forwardly declaring
> a class - simply has no equivalent purpose when it comes to enums.
As shown above classes can also be provided as by-value
arguments and do not need to be complete types at the
point of function declaration.
Actually I totally agree with Alberto, the new typed enums
would be ideal candidates to support forward-declarable enum's.
As far as I recall from earlier discussions on this theme, the
current reason for *not* supporting forward-declarable enums
is based on the conclusion that this would have the effect that
pointers to enum's would need to be of the same size. This
reason is lapsed given the current proposal to support enum's
with specified underlying types. In contrast to classes, it
would definitivly make sense to allow
enum E : int;
because the actual "members" (aka enumerators) of the
enum are not relevant for the physical "representation" of
the enum. The more I think about it, the more I like this
idea!
> > Has this issue been discussed before? Could it be considered? Is there
> > something that I'm missing?
>
> You are describing "strong" or "opaque" typedefs. See:
>
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1891.pdf
This comes somewhat near, but after a short reading I don't see how
you can simply forward declare such an opaque type without providing
a definition for it. But viewing from a different angle I would say
that
"inheriting enums" are more or less a realization of these types -
only restricted on integral representations, but that is already ok
for Alberto.
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2141.html
This is not very much related, it more or less corresponds to the
predecessor of as "inheriting constructors" described in the most
recent proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2438.htm
It's obvious that I always need the *definition* of a base class to
realize this issue.
> I am not sure whether strong typedefs will make it into C++ or not.
I don't know either. It seems the proposal has at least been
split into inheriting constructors and other parts. I don't know
which the other parts are. I will read your first provided link
completely to understand which meaning the word "opaque"
is meant here - it does not seem to mean an opaque type
that is usually meant with an incomplete type used as
a handle or similar, but I might err here.
Greetings from Bremen,
Daniel Kr gler
---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Wed, 5 Dec 2007 21:29:14 GMT Raw View
Greg Herlihy wrote:
> Because, unlike a class object, which can be passed
> by reference or pointer (and thus may be an incomplete type) - an enum
> is always referenced by value. So the practice of forwardly declaring
> a class - simply has no equivalent purpose when it comes to enums.
What do you mean? Surely I may use pointers and references to enums
in the same way as pointers and references to class objects?
---
[ 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: alfps@start.no ("Alf P. Steinbach")
Date: Wed, 5 Dec 2007 21:29:50 GMT Raw View
* Greg Herlihy:
> On Dec 4, 3:31 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>> Hi Everybody,
>>
>> in a project I am working on, we have an enumeration with several
>> hundred enumerators that is generated by an automatic tool. Each
>> enumerator represent an ID of localizable string. The localizer
>> component is accessible from several places on in the project, however,
>> only very few compilation units actually require access to the values of
>> the enumerators. Each time the automatic tool re-generate the
>> enumeration, nearly half of the project have to be re-compiled, although
>> only few compilation units would actually need it. A way to isolate the
>> enumerators while keeping the type-safety provided by the enumerated
>> type would be very useful.
>
> I think that the more straightforward approach would be to limit the
> number of source files that include the enum definition (or references
> to it, including function prototypes). Only those source files that
> need the enum definition (say, to pass as an argument in a function
> call) should include the necessary header.
You can be sure that what you describe is already applied, given
Alberto's description of the motivating problem.
A more practical approach is to introduce a namespace hierarchy and
delegate responsibility (also in the organization, not only in the
code). E.g., I can imagine that the enumeration is concerned with error
messages or communication message kind id's. And doing that centrally,
even with use of subranges and automatic generation, is in my experience
both an administrative and coding nightmare, simply a Very Bad Idea(TM),
however, it's one that seems at first to be a simple and good solution.
The interesting thing about enums in that respect, although it's just
academical, is that extending an enum (not supported by C++) would
introduce a supertype rather than a subtype.
>> The first thing that comes in mind is to "forward" declare the
>> enumeration (that is to declare the name of the enumeration without
>> listing all enumerators), like this:
>>
>> enum E; // enumerators defined elsewhere: illegal in C++03
>> void Func(E);
>
> A forward-declaration of the enum E would be pointless - because
> either a) a source file calls Func() (and therefore has to include the
> complete definition of E anyway) or b) a source file does not call
> Func() - in which case there is no reason to include either the Func()
> function prototype or the forward declaration of E - in the first
> place.
The conclusion for scenario (b) is incorrect.
For example, in header file you may need to declare a private member
function f with E argument or result.
Clients using that header file don't need the definition of E.
>> Unfortunately, that is illegal in C++03. The rationale is that without
>> the complete list of enumerators we can't determine the underlying type
>> of E. The obvious workaround is to use an integral type instead of the
>> enumeration and provide a hopefully clear comment:
>>
>> void Func(int); // actually a value of enum E should be passed here
>
> The rationale has nothing to do with the underlying type of the enum -
> and everything to do with the fact that source files fall into either
> one of the two categories mentioned above: those that require the
> complete enum definition and those that do not need the enum
> definition at all.
Presumably you're referring to the reasoning discussed above. But since
that reasoning is incorrect, it very doubtful that it can be the rationale.
> Because, unlike a class object, which can be passed
> by reference or pointer (and thus may be an incomplete type) - an enum
> is always referenced by value.
Counter-example:
enum PosterEnum { Greg, Alf };
void foo( PosterEnum& poster );
Were you thinking of some other language, like e.g. C#?
> So the practice of forwardly declaring
> a class - simply has no equivalent purpose when it comes to enums.
Sorry, even if the premise was true (which it wasn't, see above), that
conclusion would not follow.
[snip]
> You are describing "strong" or "opaque" typedefs. See:
>
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1891.pdf
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2141.html
>
> I am not sure whether strong typedefs will make it into C++ or not.
Possibly useful references so I quoted them.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ 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: Wed, 5 Dec 2007 23:02:56 GMT Raw View
Greg Herlihy ha scritto:
> On Dec 4, 3:31 pm, AlbertoBarb...@libero.it (Alberto Ganesh Barbati)
> wrote:
>> Hi Everybody,
>>
>> in a project I am working on, we have an enumeration with several
>> hundred enumerators that is generated by an automatic tool. Each
>> enumerator represent an ID of localizable string. The localizer
>> component is accessible from several places on in the project, however=
,
>> only very few compilation units actually require access to the values =
of
>> the enumerators. Each time the automatic tool re-generate the
>> enumeration, nearly half of the project have to be re-compiled, althou=
gh
>> only few compilation units would actually need it. A way to isolate th=
e
>> enumerators while keeping the type-safety provided by the enumerated
>> type would be very useful.
>=20
> I think that the more straightforward approach would be to limit the
> number of source files that include the enum definition (or references
> to it, including function prototypes). Only those source files that
> need the enum definition (say, to pass as an argument in a function
> call) should include the necessary header.
This is not always practically possible.
>> The first thing that comes in mind is to "forward" declare the
>> enumeration (that is to declare the name of the enumeration without
>> listing all enumerators), like this:
>>
>> enum E; // enumerators defined elsewhere: illegal in C++03
>> void Func(E);
>=20
> A forward-declaration of the enum E would be pointless - because
> either a) a source file calls Func() (and therefore has to include the
> complete definition of E anyway) or b) a source file does not call
> Func() - in which case there is no reason to include either the Func()
> function prototype or the forward declaration of E - in the first
> place.
This premise is wrong. A value of an enumeration could be obtained and
used without any knowledge of the enumerators, for example in this case:
--- fileA.h
enum Opaque : int; // suppose it were legal
Opaque RetrieveData();
void DoSomethingWithData(Opaque);
--- fileA.cpp
#include "fileA.h"
enum Opaque : int {
Value1, Value2, /*...*/
};
Opaque RetrieveData() { /*...*/ }
void DoSomething(Opaque o) { /*...*/ }
--- fileB.cpp
#include "fileA.h" // look Ma, no enumerators!
int main()
{
DoSomethingWithData(RetrieveData());
}
There are also other use cases. A very good one has been identified by
Daniel Kr=C3=BCgler, that is:
struct Something {
enum State : unit64_t; // Would be fine
State s; // Even this should work
};
Actually this scenario is very similar to the one I am facing in my
motivating project! The "s" member in my case is private and no methods
in the public interface of "Something" get or return values of type
"State". In this scenario there is no chance that a translation unit
including the definition of Something will ever need the actual list of
enumerators (except, of course, the one implementing the member
functions of Something.)
>> Unfortunately, that is illegal in C++03. The rationale is that without
>> the complete list of enumerators we can't determine the underlying typ=
e
>> of E. The obvious workaround is to use an integral type instead of the
>> enumeration and provide a hopefully clear comment:
>>
>> void Func(int); // actually a value of enum E should be passed here
>=20
> The rationale has nothing to do with the underlying type of the enum -
> and everything to do with the fact that source files fall into either
> one of the two categories mentioned above: those that require the
> complete enum definition and those that do not need the enum
> definition at all. Because, unlike a class object, which can be passed
> by reference or pointer (and thus may be an incomplete type) - an enum
> is always referenced by value. So the practice of forwardly declaring
> a class - simply has no equivalent purpose when it comes to enums.
I disagree, the underlying type is the key point. If you know that, you
can manipulate values of the enum even without any knowledge of what
those values mean or how they have been obtained, as I've shown in the
my first example. Indeed, there *is* a difference between class objects
and enum, that is a declared (but not defined) class object is an
incomplete type, while an enum will always be a complete type as soon as
you know the underlying type. For this reason, it's unfair to compare
enums with class objects, the correct comparison is between enums and
*pointers* to class objects. You can manipulate pointers to incomplete
types precisely because you know the representation of pointers even if
the pointed type is incomplete.
>=20
> You are describing "strong" or "opaque" typedefs. See:
>=20
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1891.pdf
> http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2141.html
No, I am not referring to those, although they address a similar issue.
An enumeration is both a type *and* a set of named values, while strong
typedefs are just types: that's a very big difference.
>=20
> I am not sure whether strong typedefs will make it into C++ or not.
>=20
Another good reason to avoid messing with them at this stage.
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: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Thu, 6 Dec 2007 12:19:14 CST Raw View
Greg Herlihy wrote:
> A forward-declaration of the enum E would be pointless - because
> either a) a source file calls Func() (and therefore has to include the
> complete definition of E anyway) or b) a source file does not call
> Func() - in which case there is no reason to include either the Func()
> function prototype or the forward declaration of E - in the first
> place.
See below
>
>> Unfortunately, that is illegal in C++03. The rationale is that without
>> the complete list of enumerators we can't determine the underlying type
>> of E. The obvious workaround is to use an integral type instead of the
>> enumeration and provide a hopefully clear comment:
>>
>> void Func(int); // actually a value of enum E should be passed here
>
> The rationale has nothing to do with the underlying type of the enum -
> and everything to do with the fact that source files fall into either
> one of the two categories mentioned above: those that require the
> complete enum definition and those that do not need the enum
> definition at all. Because, unlike a class object, which can be passed
> by reference or pointer (and thus may be an incomplete type) - an enum
> is always referenced by value. So the practice of forwardly declaring
> a class - simply has no equivalent purpose when it comes to enums.
No that is untrue. consider:
enum X {a, b, c ,d};
void func(X &);
And the implementation is:
void func(X & x){
x = a;
}
The program cannot be written in terms of passing X by value because we
want to change the X object.
---
[ 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 ]