Can two enums not have a member of similar name? - c++

I have a situation where I need two enums to hold one member of the same name. My code is in C++, Using IAR Embeddedj Workbench IDE. The code snippet is as follows:
enum Port_e : uint32_t
{
PortA = 0,
PortB,
PortC,
PortD,
PortE,
PortF,
PortG,
PortH,
PortI,
PortJ,
PortK,
NONE
};
enum Pin_e : uint32_t
{
Pin0 = 0, Pin1, Pin2, Pin3, Pin4, Pin5, Pin6, Pin7,
Pin8, Pin9, Pin10, Pin11, Pin12, Pin13, Pin14, Pin15,NONE
};
If you notice here both enums have the last member as NONE.
This code does not compile. Gives Error as NONE is already defined.
Is there any way to make it build while keeping the name as it is?
I also do not want to change the type to "enum class" as it will break the rest of my application code.

Is there any way to make it build while keeping name as it is?
Not without changes. If you wrap Port_e and Pin_e in a namespace or class you can resolve the name collision, but that would still alter the way the enums are used.
I also do not want to change the type to "enum class" as it will break the rest of my application code.
I strongly suggest you to do that anyway, and take the time to fix your application code. enum class was designed exactly to solve this problem.

You can use class enums or nest your enums in appropriate classes or namespaces.
#include <iostream>
enum class A :uint32_t { One, Two, Three };
enum class B :uint32_t { One, Two, Three };
int main()
{
std::cout << int(A::One) << std::endl;
}
Identifiers of enumeration are names of integral constants belonging to namespace enum is declared in. Class enums changed this situation, but you cant cast from and to them implicitly. Any other approach eventually would cause ODR breakage if you would use simple enogh names. In your code it leads to ambiguity: is NONE equal to 13? Or to 16?

Related

Learning C++ and having a problem correclty separating class interface from implementation

I'm learning C++ using Xcode and have written several small programs including a hangman game but I'm having trouble every time I try to separate a class into definition and implementation. I made a simple case that shows my problem. Short version is it seems that I need to specify a type in the implementation file even though it is already defined in the header file. I get "C++ requires a type specifier for all declarations" on lines 12 and 13 in my example. But if I change line 12, for example, to
int xmlelem::atrb_count = 0;
it gets the error "non-static data member defined out-of-line". In other cases I have got an error saying that I was trying to redefine something. I think I'm missing a fundamental concept somewhere. I did not see this particular issue in the handful of similar questions I looked at.
xmlelem.hpp
// xmlelem.hpp
// learn header
//
//
#ifndef xmlelem_hpp
#define xmlelem_hpp
#include <stdio.h>
#include <string>
#endif /* xmlelem_hpp */
class xmlelem {
private:
int atrb_count;
std::string tag_name;
public:
xmlelem(std::string tag);
void add_atrib();
std::string output();
};
xmlelem.cpp
// xmlelem.cpp
// learn header
//.
//
#include "xmlelem.hpp"
#include "string"
#include <iostream>
// line 11
xmlelem::atrb_count = 0;
xmlelem::tag_name = "";
xmlelem::xmlelem(std::string tag){
tag_name = tag;
}
void xmlelem::add_atrib(){
atrb_count++;
}
std::string xmlelem::output(){
std::string build = "<";
build = build + tag_name + " " + std::to_string(atrb_count);
build = build + ">";
return build;
}
and main.cpp
// main.cpp
// learn header
//
//
#include <iostream>
#include "xmlelem.hpp"
using namespace std;
int main(){
xmlelem clip("test)");
std::cout << clip.output() << " test \n";
}
Let's take a look at the (second) error message.
non-static data member defined out-of-line
There are two parts to the error: "non-static data member" and "defined out-of-line". These are incompatible, so one of them must be changed. Furthermore, only one of them should be changed, or else you may run into a different problem. Decide which of the two parts is correct for your situation.
Keep "defined out-of-line"
When the line
int xmlelem::atrb_count = 0;
is encountered at namespace scope (that is, in neither a function nor a class/struct/union definition), it is an out-of-line definition. This definition tells the compiler to reserve, right at that spot, enough space for an int. Then whenever any xmlelem object accesses the atrb_count member, it will access this particular space. So there is one int shared by all objects.
However, this behavior corresponds to a static member. To make the declaration agree with the implementation, the keyword static needs to be added.
class xmlelem {
private:
static int atrb_count;
/* rest of the class definition */
};
Keep "non-static"
A non-static data member is stored inside each object of the class. Each object can do what it wants with its copy of the data without impacting other objects. So telling the compiler to reserve space outside the objects is contradictory. Simply removing the out-of-line definition is enough to get rid of the error message, but presumably you wanted that initialization to occur somewhere, right?
The initialization of non-static data members can be done either in-line or in a constructor. An example of moving the initialization in-line is the following.
class xmlelem {
private:
int atrb_count = 0;
/* rest of the class definition */
};
This is sometimes reasonable, but the stated goal was to separate the interface from the implementation. Therefore, it might be undesirable for the initial value of 0 to appear in the header file, as it does in the above. The alternative is to move the initial value to the constructor (to each constructor, if you had more than one).
xmlelem::xmlelem(std::string tag) :
atrb_count(0),
tag_name(tag)
{
}
(I've also taken the liberty of moving the initialization of tag_name into the initialization list.)
Remember, if you have more than one constructor, this needs to be done in each constructor that actually utilizes the default value (for an exception, think "copy constructor"). Repeated code is a drawback; it is up to you to decide if the gains are worth the cost.
Remember that you are declaring a class. A class is an abstract concept. When you do this xlemem::atrb_count = 0;, you are having a concrete value on an abstract concept. Doesn't make sense, right? You don't think of a particular color when you think of the general concept of dog. Any initiliazations should be done inside the constructor, because only in the constructor is that we create a concrete object.
Therefore, you should eliminate lines 11 and 12 where you initialize these 2 attributes and your constructor code should be changed to:
xmlelem::xmlelem(std::string tag){
tag_name = tag;
atrb_count = 0;
}
Note that it isn't necessary to initialize a string to "".

Using alias from header file in corresponding source file

I just started learning more of c++ and am writing a small rendering engine as an example case study. As i started to implement more code I got annoyed by typing types like
std::vector<std::vector<int>>
over and over again. As most of you know already, this get's infinitely worse if you are looping over said vector
for (std::vector<std::vector<Tile>>::const_iterator layerRow = ...) {}
Since this is not just annoying but also very error prone, I looked into using typedefs and soon changed those into alias', following Scott Meyers advice in "More effective C++".
I got one problem now which I can't seem to wrap my head around. Given the following two files (corresponding header and source file):
map.h:
class Map
{
public:
using tileLayerVector_t = std::vector<std::vector<Tile>>;
using rawDataLayerVector_t = std::vector<std::vector<int>>;
tileLayerVector_t getTileLayer(const std::string pLayerName) const;
void generateTileMapLayer(const std::string pMapLayerName, const rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture);
}
map.cpp:
#include <map.h>
tileLayerVector_t Map::getTileLayer(const std::string pLayerName) const
{
return mapLayers.at(pLayerName);
}
void Map::generateTileMapLayer(const std::string pMapLayerName, const
rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture)
{
int tileCount = 0;
int xPos = 0;
int yPos = 0;
...
std::pair<std::string, tileLayerVector_t> tileLayer(pMapLayerName, tileMapLayer);
mapLayers.insert(tileLayer);
}
Function generateTileMapLayer() compiles fine without a problem. As soon as I implement getTileLayer() the UI is giving me an error "identifier 'tileLayerVector_t' is undefined" and the compiler is giving me some weird error about a missing ";" somewhere. This compiler error vanishes if I put getTileLayer() in comments.
I don't understand why I can use the alias within the function generateTileMapLayer() as a type definition for the hash map, but cannot use it as a return type for getTileLayer(). I put Map::tileLayerVector_t as a return type and it works. Why does it work without the namespace within generateTileMapLayer() though?
Maybe someone can help me with this. Thank you in advance!
A class defines a scope. How you access something in a given scope depends on whether you are writing code that's inside or outside that scope.
So when you make the declaration using tileLayerVector_t = ...; within class Map you are providing an alias for a new type Map::tileLayerVector.
This is why your code inside the class can use the type without qualification, but code outside cannot.
You could move your using-declarations outside the class, but that would pollute the global namespace. A better solution, I think, would be to simply qualify the types where needed:
Map::tileLayerVector_t Map::getTileLayer(...) // must qualify type here
{
tileLayerVector_t temp = ...; // inside a class method, no problem here
}
A more modern solution would be to use "type inference". I believe you need at least a C++11 compliant compiler to take advantage of this feature. My understanding is that the trailing return type allows the compiler to defer establishing the actual type until after the function signature has been generated, at which point the scope has been established.
auto Map::getTileLayer(...) -> tileLayerVector_t
{
....
}

Separate enum declaration and definition in C++11

There are several questions on these forums about the inheritance of C++ enums for extending (which is actually the thing without the logic). But what about inheritance just for setting specific values?
Currently, there is something like the following in my code:
//lib_impl.h
enum class X {
a = 13, // these values are
b = 42 // implementation dependent
}
//lib.h
#include "lib_impl.h"
void some_func(X param) {
X x = X::a;
}
I just want to avoid the dependecy of the 'lib' from its implementation. Probably, something other than enums must be used for that. As even in C++11 we have the ability only to declare forward enum name, but not its enumerators:
//lib.h
enum class X { a, b } // this is both declaration and definition, unfortunately
void some_func(X param) {
X x = X::a;
}
//lib_impl.h
#include "lib.h"
enum class X { // redefenition, compilation error
a = 13,
b = 42
}
What is the best compile-time solution for such problems?
--
As it seems to be unimplementable in c++, what is the most common way to resolve such issues? Leave the dependency of the 'lib' from the 'impl' as it is? Probably, 'impl' could be split into two parts, small which will be included before the 'lib.h' and other, bigger, to be included after it. Is it ok or I need to abandon the use of enums in favor of abstract classes?
Expose an enum with nominal values (start with 0, sequential say). Inside your library, remap these values to an internal enum with implementation dependent values (say an array for speed, using the external value as index). Reverse the mapping if you export said enum values to the outside (the reverse mapping will be slower).

Use templates to clone class types exactly?

I have a series of C++ classes that I wish to all be identical in functionality, but otherwise not related by inheritance. Effectively, these classes would differ in name only. (These classes will be thrown, and I do not want a catch clause for some base class to gobble up thrown derived objects. There will be derived classes, but I wish to create discrete sets of thrown classes that are always segregated, as far as catch blocks are concerned.)
Of course, the downside to this is duplicating source code. I don't want to have to update N copies of the same code, whenever something needs to be changed.
I have already solved the code duplication problem via #define. But I think it would aid debug-ability if I could leverage templates, instead. The only thing parameterized in the template will be the class name itself.
I attempted the following, which did not work in gcc (w/ c++0x support enabled):
template<typename ClassName>
class ClassName
{
public:
ClassName(int foo, float bar) { ... }
~ClassName() { ... }
bool SomePublicMethod() { ... }
private:
...
}
Then I would declare the actual classes with something akin to:
typedef ClassName<UnrelatedClass1> UnrelatedClass1;
typedef ClassName<UnrelatedClass2> UnrelatedClass2;
I already know that the above does not work; I am providing it as a conceptual example of what I would like to accomplish, and am wondering if there is a way to make it work, other than the #define macro method that I am presently using (which suffers from diminished debug-ability.)
Use value specialized template:
template<int ID>
class ClassName
{
public:
ClassName(int foo, float bar) { ... }
~ClassName() { ... }
bool SomePublicMethod() { ... }
private:
...
}
typedef ClassName<1> UnrelatedClass1;
typedef ClassName<2> UnrelatedClass2;
This doesn't sound like a very good idea at all.
Exceptions classes should capture a specific type of error, with inheritance used to more generalise the type of error.
So for example you might have a 'disk crashed exception', which more generally might be a 'disk exception' and more generally and 'io exception' and always at its core an 'std::exception'
If all your exceptions are catching different types/classes of error, then why would they all have the same type of implementation.
Also it's uncommon to see #define mixed in the templates because that invariably makes it less readable when there is a compiler error (even if it seems more readable when it is no causing errors).
Perhaps you could provide more information about what is implemented in your exception classes, and I can see if I can help you further.
I do agree with others when they say that you should use inheritance. It is great for many purposes (one of them being the reason why you would like to have similar classes). It is not compulsory to write derived classes only when the objects are related - it is great even if just the functionality that is matching because your idea really is to put similar code together.
However, since your query was about creating multiple classes and we do not have enough view of your project, I believe it is possible that you may really need separate classes. One way of doing this is through macros. Here's a sample:
#include <iostream>
using std::cout;
using std::endl;
#define CUSTOM_CLASS(_CL) class _CL\
{\
public:\
_CL(int foo, float bar) { cout << "Creating instance with foo=" << foo << ";bar=" << bar << endl;}\
~_CL() { }\
bool SomePublicMethod() { cout << "Class created\n"; }\
};
CUSTOM_CLASS(myclass1);
CUSTOM_CLASS(myclass2);
int main()
{
myclass1 instance1(1, 1.3f);
myclass2 instance2(2, 0.3f);
return 0;
}
If you run this using g++, you will get the following result:
Creating instance with foo=1;bar=1.3
Creating instance with foo=2;bar=0.3

Map one enum to another enum

There is an existing enum
typedef enum
{
myEnum_front = 11,
myEnum_back = 19
} myEnumSides;
I want to create another enum new_myEnumSides and it's values should be mapped to the values of myEnumSides. Hence forth I would be using new_myEnumSides instead of myEnumSides.
Is the code below ok for this purpose?
typedef enum
{
new_myEnum_front = myEnumSides::myEnum_front,
new_myEnum_back = myEnumSides::myEnum_back
} new_myEnumSides;
Or is there a better way?
I can't possibly imagine why do you need to do it... If you don't need to rename the enum's values, you can just make another variable of the first one, without adding another enum (I believe this is not your case, but still have to point out this opportunity):
typedef enum
{
myEnum_front = 11,
myEnum_back = 19
} myEnumSides, new_myEnumSides;//<-- just add the new variable here
If you do want to rename it (which I believe, is your case), you should not use the :: operator, but simply write:
typedef enum
{
myEnum_front = 11,
myEnum_back = 19
} myEnumSides;
typedef enum
{
new_myEnum_front = myEnum_front,
new_myEnum_back = myEnum_back
} new_myEnumSides;
The :: operator should be used only if the enum is inside a class, structure or namespace, otherwise no :: is needed.
The only reason I can imagine you wanting to do this is to extend an existing enum and create a new one with extra values.
As enum does not offer any form of inheritance, being compile time constants and really just integers, you could do something like this, although I don't particularly recommend it..
// internalEnums.h
myEnum_front = 11,
myEnum_back = 19
// customerEnums.h
someNewValue = 20,
someOtherNewValue = 21
// Wherever you want to define your enums
typedef enum
{
#include "customerEnums.h"
} customerAccessible;
typedef enum
{
#include "internalEnums.h"
#include "customerEnums.h"
} internalUseOnly;
// Now there are two enumerations, sharing items.
customerAccessible::someNewValue // 11
customerAccessible::myEnum_front; // Doesn't exist
EDIT As per your comment, you could expose enumerations to the customer by keeping values in a header specifically for external use.
It's usually the case that you don't want to expose details of third party libraries, but an enumeration that lies there might have the exact members you need.
In that case it's beneficial to create a mapping for the third party enum, so that even if the backend library changes, you can simply provide the enumerators yourself.
The most concise way to do this, is by creating an alias:
using MyEnum = ThirdPartyEnum;
// {
// enumerator1,
// enumerator2
// }
This way, user code won't rely on third party internals,
you avoid doing conversions and even if the third party library is replaced, your users can keep using MyEnum by simply uncommenting the enumerator values (I like to keep them in comments, so users won't have to refer to third party libraries for documentation.