Access struct enum from object - c++

I am just learning to use c++ and I'm trying to understand how scope works with classes and embedded enums.
Currently I have a class which looks something like this:
class Foo {
public:
Foo();
enum Option = {
FIRST,
SECOND,
THIRD
};
struct Example = {
const char* name;
Option key;
enum keyOption = {
PROPERTY,
FLAG
} keyValue;
};
};
Then in my main function I initialize it and then add some values to the Example struct
int main()
{
Foo *test;
Foo::Example content = {
"Hello World",
test->FIRST,
test->Example::PROPERTY
};
}
With the above code I will get an error of:
error: 'Foo::keyOption' is not a base of 'Foo'
I know I can fix it by changing test->Example::PROPERTY to Foo::Example::PROPERTY
But is there a way I can access the Example structs values through the object instead of Foo::? Similarly to how I access the FIRST value?
Forgive me if I'm butchering the naming of difference concepts, I'm just trying to teach myself by building something, and I will need to read more into the details soon.
Thank you so much for any help, it is really appreciated!

Foo::FIRST and Foo::Example::PROPERTY are possible values of the enumerator. Only Example::key and Example::keyValue are members of the struct which can be instantiated and initialized to Foo::FIRST and Foo::Example::PROPERTY

This should work
Foo::Example content = {
"Hello World",
test->FIRST,
Foo::Example::PROPERTY
};

Related

C++ question: what is "class UserDefinedType* MemberName;" when declared as a property of a class?

I would expect the declaration of a user-defined type member variable (a pointer to be specific) to look something like:
...
public:
UserDefinedType* MemberName;
...
But I've seen this in a few examples:
...
public:
class UserDefinedType* MemberName;
...
Apologies for what I'm sure is an obvious question to answer, I just don't really know what to search for. I've looked at nested classes in C++, but I'm unsure if that's what is happening here. Honestly feels like a somewhat redundant identifier.
Any comments, links, corrections, are appreciated thank you.
That's a forward declaration
class UserDefinedType {
};
class A {
public:
UserDefinedType * member1; // this is ::UserDefinedType
class UserToBeDefinedType; // forward declaration
UserToBeDefinedType * member2; // this is A::UserDefinedType
};
class A::UserToBeDefinedType { // define the class
};
int main()
{
A a;
a.member1 = new UserDefinedType; // OK
//a.member2 = new UserDefinedType; // KO
//a.member1 = new A::UserDefinedType; // KO
a.member2 = new A::UserToBeDefinedType; // OK
}
Run and test the code
Maybe read this
EDIT: Enhance the quality of example and add link to run code

C++ data structure where initialization can use its names

I need to create a data structure that has a LOT of members. Example:
struct MyStruct {
int varSomething;
int helloNumber;
int thisIsSomething;
...
int varNumber50;//50th element
}
The problem with this struct is that when I want to instantiate it, I need to do the following:
my_vector[i] = MyStruct{10, 4, 90, ...}
as you can see, I need to put lots of values and I end up confusing which one is which. Ideally, I'd like to do something like this:
my_vector[i] = MyStruct{varSomething = 10, helloNumber = 4, thisIsSomething = 90, ...}
Since each variable has a name, I know what I'm doing, and can't confuse.
I know that I can do this:
MyStruct myStruct;
MyStruct.varSomething = 10;
myStruct.helloNumber = 4;
...
my_vector[i] = myStruct
but I want to create an anonymous struct, it's not nice to create a named struct just to put in the vector.
What should be a great way to solve this problem? Is there something similar to a struct that can achieve what I want??
With c++20 designated initializers you can do the following
struct MyStruct {
int a,b,c;
};
int main(){
MyStruct my_value {
a : 2,
b : 3,
c : 95
};
}
In this case I would recommend against using this as it is a definite code smell.
You need to rethink your design and maybe looking at design patterns like factory, builder or prototype to give you a better idea on how to create your objects.
See the following links for more information:
https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
https://en.wikipedia.org/wiki/Creational_pattern

C++ Assign std::map values with enum class object

Consider following code.
In my real case scenario i have somthing like that:
typedef enum
{
vehicle,
computer,
} Article;
And that is what I'm trying to construct:
enum class status{
notPaid,
paid,
};
struct S {
status status_vehicle;
status status_computer;
std::map<Article, status> mymap =
{
{vehicle, S::status_vehicle},
{computer, S::status_computer},
};
};
int main ()
{
Article a1 = vehicle;
S::mymap.at(a1) = status::paid; // this line doesn't work
}
However, the last line (S::mymap.at(a1) = status::paid;) is not working. I've tried different approaches, using the find() function of std::map for example. I got the error "assignment of member std::pair<Article, status>::second in read only object".
Does someone know, how to do that? Also maybe how to design the whole in a better way? (the whole from the line "And that is what I'm trying to construct").
Also I would have prefer to use an unordered_map instead of a map but was not working. Thanks
Because mymap is not static.
You can do like this:
Article a1 = vehicle;
struct S mystruct;
mystruct.mymap.at(a1) = status::paid;
Or add static to your member in struct:
struct S {
status status_vehicle;
status status_computer;
static std::map<Article, status> mymap;
};
But when using static, you have to initialize mymap outside declaration of struct S and member that you can't use non-static members of struct
std::map<Article,status> S::mymap={
{vehicle,S::status_vehicle}
};
A static member is shared by all objects of the class. All static data
is initialized to zero when the first object is created, if no other
initialization is present
And logically is not good in your example
https://en.cppreference.com/w/cpp/language/static
Since myMap is non-static, it cannot be assigned as static variables are.
You can change your code like this:
int main ()
{
Article a1 = vehicle;
S ss;
ss.mymap.at(a1) = status::paid;
}

C++ : nameable objects belonging to an instance of a class, and stored in it

I am trying to make it possible for a programmer (who uses my library) to create nameable instances of type X that are stored inside an instance of class C (or at least are exclusive to that instance).
These are the only two (ugly) solutions I have managed to come up with (needless to say, I am just picking up C++)
1)
class C
{
public:
class XofC
{
public:
XofC() = delete;
XofC(C& mom)
{
mom.Xlist.emplace_front();
ref = Xlist.front();
}
X& access()
{
return ref;
}
private:
X& ref;
};
//etc
private:
std::forward_list<X> Xlist;
friend class XofC;
//etc
}
Problem:
Having to pass everywhere XofC instances.
2)
class C
{
public:
void newX(std::string);
X& getX(std::string);
//etc.
private:
/*possible run-time mapping implementation
std::vector<X> Xvec;
std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
*/
//etc
}
Problem:
This does the job, but since all names of X (std::string) are known at compilation, the overhead of using run-time std::unordered_map<std::string, decltype(Xvec.size())> kind-of bugs me for something this simple.
Possible(?) solution: compile-time replacing of std::string with automatic index (int). Then I could use:
class C
{
public:
void newX(int); //int: unique index calculated at compile time from std::string
X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
std::vector<X> Xvec;
}
Questions:
Is there a 3)?
Is a compile time solution possible for 2)?
This is the real-life situation: I was starting my first C++ "project" and I thought I could use the practice and utility from an awesome user-friendly, simple and fast argument management library. I plan to make an ArgMan class which can parse the argV based on some specified switches. Switches would be named by the programmer descriptively and the trigger strings be specified (e.g. a switch named recurse could have "-r" and "-recursive" as triggers). When necessary, you should be easily able to get the setting of the switch. Implementation detail: ArgMan would have a std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. This ensures an almost linear parse of argV relative to argC. How should I approach this?
You could 'abuse' non-type template arguments to get compiletime named instances:
Live on Coliru
Assume we have a data class X:
#include <string>
struct X
{
int has_some_properties;
std::string data;
};
Now, for our named instances, we define some name constants. The trick is, to give them external linkage, so we can use the address as a non-type template argument.
// define some character arrays **with external linkage**
namespace Names
{
extern const char Vanilla[] = "Vanilla";
extern const char Banana [] = "Banana";
extern const char Coconut[] = "Coconut";
extern const char Shoarma[] = "Shoarma";
}
Now, we make a NamedX wrapper that takes a const char* non-type template argument. The wrapper holds a static instance of X (the value).
// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
struct NamedX
{
static X value;
};
template <const char* Name> X NamedX<Name>::value;
Now you can use it like this:
int main()
{
X& vanilla = NamedX<Names::Vanilla>::value;
vanilla = { 42, "Woot!" };
return vanilla.has_some_properties;
}
Note that due to the fact that the template arguments are addresses, no actual string comparison is done. You cannot, e.g. use
X& vanilla = NamedX<"Vanilla">::value;
becuase "Vanilla" is a prvalue without external linkage. So, in fact you could do without some of the complexity and use tag structs instead: Live on Coliru
While Neil's solution did what I asked for, it was too gimmicky to use in my library. Also, sehe's trick is surely useful, but, if I understood correctly, but doesn't seem related to my question. I have decided to emulate the desired behavior using method 1), here is a less broken attempt at it:
class C
{
private:
class X
{
//std::string member;
//etc
};
public:
class XofC
{
public:
XofC(C & _mom) : mom(_mom)
{
mom.Xlist.emplace_front();
tehX = &(Xlist.front());
}
X & get(maybe)
{
if (&maybe != &mom) throw std::/*etc*/;
return &tehX;
}
private:
X * tehX;
C & mom;
};
private:
//etc
std::forward_list<X> Xlist;
friend class XofC;
//etc
};
Usage:
C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";
Of course, the downside is you have to make sure you pass bar everywhere you need it, but works decently.
This is how it looks like in my tiny argument manager library:
https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h

Using enum inside types - Compiler warning C4482 C++

I am using fully qualified name of the enum inside a method in one of my class. But I am getting compiler warning which says "warning C4482: nonstandard extension used: enum 'Foo' used in qualified name". In C++, do we need to use enums without the qualified name? But IMO, that looks ugly.
Any thoughts?
Yes, enums don't create a new "namespace", the values in the enum are directly available in the surrounding scope. So you get:
enum sample {
SAMPLE_ONE = 1,
SAMPLE_TWO = 2
};
int main() {
std::cout << "one = " << SAMPLE_ONE << std::endl;
return 0;
}
To make it clean, replace:
enum Fruit {
ORANGE = 0,
BANANA = 1
};
with
namespace Fruit {
enum { //no enum name needed
ORANGE = 0,
BANANA = 1
};
};
...
int f = Fruit::BANANA; //No warning
While sth does answer the question, it didn't address how I've always used enums. Even though they're just more or less names for numbers, I've always used them to define types that can only have certain values.
If the enum is part of the class, then that helps consumers clearly identify an enum reference:
class Apple {
enum Variety {
Gala,
GoldenDelicious,
GrannySmith,
Fuji
}
...
};
Then consumers would be able declare instances of the enum, pass as parameters, and qualify them when referencing one of the types.
unsigned int GetCountOfApples( Apple::Variety appleVariety );
...
fujiCnt = GetCountOfApples( Apple::Fuji );
Sometimes you want an enum outside of a class or two enums in the same class, and you can do something like what Poy had. You won't be able to reference the enum type though, so just name it.
namespace Color {
enum ColorEnum {
Blue,
Red,
Black
};
Now using the enum and values would work like:
Color::ColorEnum firstColor = Color::Blue;
Color::ColorEnum secondColor = Color::Red;
if( firstColor == secondColor )
....
Now if there happens to be different enums with the same name in them, they will always be qualified with what type they are. Then you could handle what gamblor is asking about.
BananaColorEnum banCol = BananaColor::Yellow;
TomatoColorEnum tomCol = TomatoColor::Yellow;
Yes. Conceptually enum defines a type, and the possible values of that type. Even though it seems natural, to define enum foo { bar, baz }; and then refer to foo::baz is the same as referring to int::1.
namespace Company
{
typedef int Value;
enum
{
Microsoft= 0,
APPLE = 1,
};
};
namespace Fruit
{
typedef int Value;
enum
{
ORANGE = 0,
BANANA = 1,
APPLE = 2,
};
};
...
Fruit::Value f = Fruit::BANANA; //No warning
Company::Value f = Company::APPLE; //is different value then Fruit::APPLE
This works on GCC and MS compiler and Mac. And the advantage is that you can use namespace operator and pass conflicts. The little disadvantage is that instead of Fruit, you have to write Fruit::Value. it is more useful in large project when you don't know what enums are in other class.
If it is possible to use C++11 instead, it is much more simple, because the enum::namespace syntax is then possible.
The cleanest way I've found to do this is defining the enum as such
namespace Samples
{
enum Value
{
Sample1,
Sample2,
Sample3
};
}
typedef Samples::Value Sample;
Then in function and variable definitions you can use the typedef:
void Function(Sample eSample);
Sample m_eSample;
And in your .cpp file you can use the namespace to assign variables:
void Function(Sample eSample)
{
m_eSample = Samples::Sample1;
eSample = Samples::Sample2;
}
Personally, I think this is a compiler bug. I've been using C++ for lots of time. Sadly, no sample code in OP. The interpretation of an enum by the Java people was actually correct iMO. Mine, was like this ...
class Foo {
enum tMyEnum { eFirstVal = 0, eSecondVal = 1};
// ...
tMyEnum m_myVal;
};
void Foo::MyMethod() {
if(m_myVal == tMyEnum::eFirstVal) {
// ...
}
}
I also tried, Foo::tMyEnum::eFirstVal. Without the qualifiers, everything compiled.
I had the same problem and I'm not using C++ 11 yet. I much prefer fully qualified namespaces myself too.
I disabled this particular warning. I'm sure people will dislike the idea but some may be thankful..
#pragma warning( disable : 4482 )