The correct way to use enumerations with passing by value and returning to functions?

I understand that the title of the question is very vague, therefore, the main text :)

I have several enum that I use to identify file types and other materials that need to be easily differentiated. My previous approach was as follows:

 namespace my_namespace { namespace fileType { enum fileType { SOURCE, HEADER, RESOURCE }; } } using namespace my_namespace::fileType; 

This allowed me to define a function:

 fileType someFunction( const std::string &someFile, const fileType someType ) { //... return fileType::HEADER; } 

And I could define and compare such variables:

 fileType type = fileType::SOURCE; 

It's amazing. Although there were some reservations. The headers (without any using directives) required doubling the intended enumeration name so that the compiler knew that you were using a type and not a namespace:

 my_namespace::fileType::fileType soeFunction( const std::string &someFile, const my_namespace::fileType::fileType someType ); 

What looks silly is hard to read and painful to understand. In addition, MSVC complains about a level one warning about the non-standard extension used (due to doule fileType in the example). It is strange that GCC does not complain about the most stringent settings, but, hey, this is a different story.

Now I want to rewrite my enum so that they (anonymously) are enclosed in a structure instead of a namespace, which allows using one qualification when declaring functions, thereby closing the MSVC warning. But how to write a return in this case. Is this absolutely necessary to provide a constructor / conversion operator, or is there a way I have not circumvented this?

Example:

 // enum definition namespace my_namespace { struct fileType { enum { SOURCE, HEADER, RESOURCE }; } } using my_namespace::fileType; // function declaration in header my_namespace::fileType someFunction( const std::string &s, const my_namespace::fileType type ); // function implementation in .cpp file using my_namespace::fileType; fileType someFunction( const string &s, const fileType type ) { //...(problem is situated below) return fileType::SOURCE; } 

This illustrates what I would like to do. I would like to avoid explicitly calling the fileType(fileType::SOURCE) enum: fileType(fileType::SOURCE) constructor, which would leave me using double fileType .

Thanks for the help!

PS: if this question has already been answered, I apologize, but I did not find a good alternative with Google or previous SO questions on this issue.

+2
c ++ enums struct namespaces c ++ 11
Feb 05 2018-11-15T00:
source share
3 answers

Personally, I use a very simple trick:

 struct EnumName { enum type { MemberOne, MemberTwo, ... }; }; typedef EnumName::type EnumName_t; // Usage EnumName_t foo = EnumName::MemberOne; 

In C ++ 0x, you can have limited enumerations directly:

 enum struct EnunName // note: struct and class equivalent here { MemberOne, MemberTwo, ... }; // Usage EnumName foo = EnumName::MemberOne; 

That will be really cool :)

Note: copied transfers are also not subject to integral advertising, which is really great

+9
Feb 05 2018-11-15T00:
source share

From my point of view, having a namespace or structure that contains nothing but one enumeration has already proved that a namespace / structure is useless. So you should just give it up.

You should try if

 namespace my_namespace { enum fileType { SOURCE, HEADER, RESOURCE }; } 

suits you better. Quite often, although in this case, programmers like the prefix of the actual values ​​of enum with the name enum, resulting in

 namespace my_namespace { enum fileType { FILE_TYPE_SOURCE, FILE_TYPE_HEADER, FILE_TYPE_RESOURCE }; } 

here you can even choose to rename the listing itself to

  enum FILE_TYPE { ... 

Also, enumerations are best used for a group of values ​​that are themselves incomplete and will never be expanded in the future, for example. listing for weekdays.
If you think the fileType enumeration file is likely to be forever incomplete (since there are hundreds of file types), you can use another approach - use persistent groups. Using constant groups takes precedence over an enumeration: if you extend this constant group, you only need to recompile modules / files that use the newly added values, whereas if you add a value to an enumeration, you may need to recompile all sources that use this enumeration.

A permanent group might look like this:

 namespace nms { typedef const unsigned short fileType_t; namespace fileType { fileType_t SOURCE = 1; fileType_t HEADRE = 2; fileType_t RESOURCE = 3; } } 

Of course, if you prefer, you can move the typedef statement to the fileType namespace or completely get rid of it and use the "const unsigned short" directly throughout the world.

Since I don't have a compiler at home, the code above cannot compile from scratch. But I am sure that you will understand this idea.

With this approach, the source code should look like this:

 using nms; nms::fileType_t someFunction( const string &s, const nms::fileType_t type ) { return nms::fileType::SOURCE; } 
0
Feb 05 '11 at 16:40
source share

True, if you want different enumerations in the same area to have the "last" element, this is not possible. In this case, you will need the prefix "last" value with the name enum, for example (similar to the second listing example.

Regarding the presence of the “last” entry for checking arguments, I may have missed your point. For example, if you pass enum as an argument to a function, for example.

 void f( enum fileType type ) 

It does not provide more "type security" than fileType has without a "last" element.

The only reason I can see the last element (and then for the first element!) Is if you want to iterate over the elements of the enumeration elements in a loop. For example:

 enum E { first, e1 = first, e2, e3, last } for (int i = first; i < last; ++i) ... 

if so, is it not too artificial to want to have two different enumerations with the same name as the last element? Where is the advantage of having one “last” in two different enumerations?
Does its readability improve compared to, for example, E_last and F_last?
Or does it help keep a record of even one line of code?
Also, what is the “last” in parentheses used for? Copied enumerations are not converted to int by default. (But maybe I misunderstood what you wanted to do ...)

About "you cannot keep the enumeration values ​​short ..." I'm afraid I did not understand what you wanted to say here. Was it about me using "const unsigned short" in the constant group example?

And do not get me wrong, in your case (wanting to process file types) I advocated the use of persistent groups. And with them it is easy and natural to use the same "first" and "last" member (but with different meanings) in different groups. Cm.

 namespace nms { typedef const unsigned short G1_t namespace G1 { G1_t first = 1; G1_t type1 = 1; G1_t type2 = 2; G1_t type3 = 3; G1_t last = 3; } typedef const long G2_t namespace G2 { G1_t first = -1; G1_t obj1 = -1; G1_t obj2 = 0; G1_t obj3 = 1; G1_t last = 1; } } 

As for "namespace - namespace - enum", I don't like the additional indirectness without significant advantages. As for "namespace - struct / class - enum", this is more philosophical:

C is, so to speak, a sleek and fast bike that made the assembler code written almost unnecessary. It also pretty much belongs to the C lithography operator, which allows you to completely abandon type safety and do what you want without getting the compiler in your path.

C ++ still loves to be a super-set of C. He added classes and object-oriented programming, but still wanted to keep the bike. That was good. Now adding more “safe types” of censuses while maintaining cast operators seems like a desire to add airbags and seat belts to a motorcycle.

I am not against revising transfers to get better transfers (if this is true), but if so, sometimes it is necessary (for example, every 5 years) to discard things that are now recognized as old, obsolete and evil. Otherwise, the language becomes more and more confusing and more difficult for beginners to learn. And, like all programming languages, you need to be easy to use, and this includes not a dozen ways to do the same.

0
Feb 05 2018-11-11T00:
source share



All Articles