在函数中使用带有值传递和返回的枚举的正确方法?
我知道问题标题非常模糊,因此正文:)
我有几个用于识别文件类型和其他需要轻松区分的内容的枚举。我以前的方法是这样的:
namespace my_namespace
{
namespace fileType
{
enum fileType
{
SOURCE,
HEADER,
RESOURCE
};
}
}
using namespace my_namespace::fileType;
这允许我定义一个函数:
fileType someFunction( const std::string &someFile, const fileType someType )
{
//...
return fileType::HEADER;
}
我可以像这样定义和比较变量:
fileType type = fileType::SOURCE;
这太棒了。尽管有一些警告。标头(没有任何 using
指令)需要将预期的枚举名称加倍,以使编译器知道您正在使用该类型,而不是命名空间:
my_namespace::fileType::fileType soeFunction( const std::string &someFile, const my_namespace::fileType::fileType someType );
这看起来很愚蠢,难以阅读且难以理解。此外,MSVC 在一级警告中抱怨使用了非标准扩展(由于示例中的 doule fileType
)。奇怪的是 GCC 不会在最严格的设置下抱怨,但是嘿,这是一个不同的故事。
我现在想重写我的枚举,使其(匿名)包含在结构体而不是命名空间中,从而在声明函数时允许单一限定,从而关闭 MSVC 的警告。但是在这种情况下我该如何编写 return
语句呢?是否绝对有必要提供构造函数/转换运算符,或者有没有办法解决这个问题,我没有看到?
示例:
// 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;
}
这说明了我想做的事情。我想避免显式调用枚举结构的构造函数: fileType(fileType::SOURCE)
这会让我有双重 fileType
使用。
感谢您的帮助!
PS:如果这个问题之前已经被回答过,我很抱歉,但我没有在谷歌上找到一个好的替代方案,也没有在SO之前关于这个主题的问题上找到一个好的替代方案。
I understand the question title is mightily vague, hence the body text :)
I have several enum
s I use for identifying file types and other stuff that needs easy differentiating. My former approach was this:
namespace my_namespace
{
namespace fileType
{
enum fileType
{
SOURCE,
HEADER,
RESOURCE
};
}
}
using namespace my_namespace::fileType;
Which allowed me to define a function:
fileType someFunction( const std::string &someFile, const fileType someType )
{
//...
return fileType::HEADER;
}
And I could define and compare variables like this:
fileType type = fileType::SOURCE;
Which is awesome. Though there were some caveats. Headers (without any using
directives) required doubling the intended enum name to let the compiler know you're using the type, not namespace:
my_namespace::fileType::fileType soeFunction( const std::string &someFile, const my_namespace::fileType::fileType someType );
Which does look silly, is hard to read and painful to understand. Additionally, MSVC complains at warning level one about a non-standard extension used (due to the doule fileType
in the example). Strange that GCC does not complain at the strictest settings, but hey, that's a different story.
I now want to rewrite my enum
s in a way that they are (anonymously) enclosed in a struct instead of a namespace, allowing for the single qualification when declaring functions, thus shutting up MSVC's warning. But How do I write the return
statement in this case. Is it absolutely necessary to provide a constructor/conversion operator or is there a way around this I did not see?
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 illustrated what I'd like to do. I'd like to avoid explicitely calling the enum struct's constructor: fileType(fileType::SOURCE)
which would leave me with a double fileType
use.
Thanks for the help!
PS: if this question has been answered before, I apologize, but I didn't find a good alternative with google or on SO's previous questions on this subject.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
就我个人而言,我使用一个非常简单的技巧:
在 C++0x 中,您可以直接拥有作用域枚举器:
这真的很棒 :)
注意:作用域枚举也不受积分提升的影响,这真的很棒
Personally I use a very simple trick:
In C++0x, you can have scoped enumerators directly:
Which will be really great :)
Note: scoped enum are also not subject to integral promotion, which is really great
从我的角度来看,拥有一个名称空间或一个除了单个枚举之外不包含任何内容的结构已经证明名称空间/结构是无用的。因此你应该简单地放弃它。
你应该尝试一下
如果更适合你, 。通常情况下,在这种情况下,程序员喜欢在实际的枚举值前面加上枚举的名称,因此
您甚至可以选择将枚举本身重命名为
枚举更适合用于本身不完整且从不存在的值组将来会扩展,例如工作日的枚举。
如果您认为枚举 fileType 可能永远不完整(因为有数百种文件类型),您可能需要采取另一种方法 - 使用常量组。使用常量组比枚举具有优势,如果扩展该常量组,则只需重新编译使用新添加值的模块/文件,而如果向枚举添加值,则可能需要重新编译使用的所有源那个枚举。
常量组可能如下所示:
当然,如果您愿意,可以将 typedef 语句移至 fileType 命名空间中,或者完全删除它并直接在任何地方使用“const unsigned short”。
由于我家里没有编译器,因此上面的代码可能无法从头开始编译。但我相信你会明白这个想法。
使用这种方法,您的源代码应如下所示:
From my point of view having a namespace or a struct that does not contain anything but a single enum has already proven that namespace/struct to be useless. Thus you should simply drop it.
You should try if
suits you better. Often enough though in that case programmers like to prefix the actual enum values with the name of the enum thus resulting in
here you may even choose to rename the enum itself to
Also enums are better used for group of values that are in itself incomplete and never to be extended in the future, e.g. an enum for weekdays.
If you consider that an enum fileType is likely to be eternally incomplete (since there are hundreds of files types out there) you may want to take yet another approach - use constant groups. Using constant groups has the advantage over enum that if you extend that constant group you need only recompile modules/files that make use of the new added values, whereas if you add a value to an enum you may be required to recompile all sources that uses that enum.
A constant group may look like this:
Of course if you prefer you can move the typedef statement into the fileType namespace or get rid of it completely and use 'const unsigned short' directly everywhere.
Since I don't have compiler at home the above code might not compile from scratch though. But I'm confident that you'll get the idea.
With this approach your source code should read like this:
确实,如果您希望同一范围内的不同枚举具有“最后”成员,则无法完成。在这种情况下,您需要在“最后”值前加上枚举名称作为前缀(类似于第二个枚举示例。
至于为参数检查使用“最后”条目,我可能错过了您的观点。例如,如果您将枚举作为参数传递给函数,例如,
它不提供比没有“最后一个”元素的 fileType 更多的“类型安全”。
这是我可以看到最后一个元素(以及第一个元素!)的唯一原因。是如果您确实想在循环中迭代枚举元素的元素,例如:
如果是这种情况,那么想要两个不同的枚举在哪里列出相同的名称是不是很不自然?在两个不同的枚举中拥有一个“最后”的优点是什么?
与例如 E_last 和 F_last 相比,它是否提高了可读性?
或者它是否有助于节省编写一行代码?
另外,在作用域枚举中使用“last”有何用途?默认情况下,作用域枚举不会转换为 int。 (但也许我误解了你想要做什么......)
关于“你不能保持枚举值简短......”恐怕我没有明白你想说的。是关于我在常量组示例中使用“const unsigned Short”吗?
另外不要误会我的意思,在你的情况下(想要处理文件类型)我建议使用常量组。使用它们,可以轻松自然地在不同组中使用相同的“第一个”和“最后一个”成员(但具有不同的值)。请参阅
至于“命名空间 - 命名空间 - 枚举”,我不喜欢额外的间接寻址,但没有实质性的好处。至于“命名空间 - 结构/类 - 枚举”,这更具哲学性:
可以说,C 是一辆光滑而快速的摩托车,几乎不需要编写汇编代码。这也很大程度上属于 C 强制转换运算符,它允许完全放弃类型安全并做你想做的事情,而不会让编译器妨碍你。
C++ 仍然想成为 C 的超集。它添加了类和面向对象编程,但仍然想保留摩托车。这是一件好事。现在添加更多“类型安全”作用域枚举,同时仍然保留演员操作员,在我看来就像想在摩托车上添加安全气囊和安全带。
我并不反对修改枚举以获得更好的枚举(如果确实需要的话),但如果这样做的话,也应该偶尔(例如每 5 年)放弃现在被认为是旧的、过时的和邪恶的东西。否则,语言就会变得越来越混乱,初学者也越来越难学。就像每一种工具编程语言都需要易于使用,这包括不能有十几种方法来做同样的事情。
True, if you want different enums in the same scope to have a 'last' member it can not be done. In that case you would need to prefix that 'last' value with the name of the enum for example (similar to the second enum example.
As for having a 'last' entry for argument checking I may have missed your point. For example if you pass the enum as argument to a function e.g.
It does not provide more 'type safety' than fileType has without a 'last' element.
The only reason I can see for a last element (and then for a first element as well!) is if you do want to iterate over the elements of the enum elements in a loop. For example:
if that is the case isn't it rather artificial to want to have two different enums have the same named 'last' element listed? Where is the advantage of having one 'last' in two different enums?
Does it improve readability compared to e.g. having E_last and F_last?
Or does it help to save writing even a single line of code?
Also what is using 'last' in scoped enums for? Scoped enums do not convert to int by default. (But maybe I misunderstood what you wanted to do...)
About "you can't keep the enum values short..." I'm afraid I did not get what you wanted to say here. Was it about me using 'const unsigned short' in the constant group example?
Also don't get me wrong, in your case (wanting to handle file types) I advocated to use constant groups. And with them it is easy and natural to use the same 'first' and 'last' member (but with different values) in different groups. See
As for 'namespace - namespace - enum' I dislike the additional indirection without having substantial benefits. As for 'namespace - struct/class - enum', that is more philosophical:
C is, so to speak, a slick and fast motorbike that made writing assembler code virtually unnecessary. This is also pretty much owned to the C cast operator which allows to completely drop type safety and do what you want without getting the compiler in your way.
C++ still likes to be a super set of C. It added classes and object oriented programming but still wanted to keep the motorbike. Which was a good. Now adding more 'type safe' scoped enums while still keeping cast operators looks to me like wanting to add airbags and safety belts to the motorbike.
I am not against revising enums to get better enums (if needs really be), but if one does so one should also occasionally (e.g every 5 years) drop the stuff now recognized as old, outdated and evil. Otherwise the language just gets more and more cluttered and ever so harder to learn by beginners. And like every tool programming languages need to be easy to use and that includes not having a dozen ways to do the same thing.