Get the name of an instance of a class in C++? - c++

Lets say we have this class
class IntArray {
string name;
};
and we have this driver
int main(){
IntArray xe;
return 0;
}
Basically, how would we store that name of the instance, the "xe" through the constructor and into the data member "string name"?

C++ does not support doing this. Variable names are only something you as a developer are aware of. The compiled program doesn't have them. Your std::string name field inside the class IntArray would not hold "xe"; it would just be uninitialized.
You could, however, use a map - an std::unordered_map<std::string, IntArray> arrays to be exact - and then use arrays["xe"] to access the array you like using a runtime-defined string. See std::unordered_map on CPPReference for details.

#include <string>
class IntArray
{
std::string name;
public:
IntArray(std::string name) : name{ std::move(name) } {}
};
int main()
{
IntArray xe{ "xe" };
}

Well, you have some trick to solve your problem. Instead of using directly the constructor, just use a macro, like:
#define DECL(x) x(#x)
in some common header you #include in your application. Instead of declaring
IntArray ex;
do
IntArray DECL(ex);
on expansion, you will get something like:
IntArray xe("xe");
you can also use the variadic macro expansion of latest standards to be able to call a different constructor.
#define DECL(name, ...) name(#name, #__VA_ARGS__)
If you want, you can also include the type in the macro, so:
#define DECL(type, name) type name(#type, #name)
and declare your variable with:
DECL(IntArray, ex);
That will expand to:
IntArray ex("IntArray", "ex");
this trick is far from complete, but can help you to avoid mistakes because of mispelling variable names as a consequence of having to write twice in source code.

Related

Reflection in c++ - print all the defined strings in a class

Assume I have:
#include <iostream>
class Greeter
{
public:
void printEm() {...}
private:
std::string a = "Hello!";
std::string b = "Hi!";
int IAmNotAString = 0;
};
What is the simplest way to get printEm to print all the defined strings in Greeter, and further, should someone define a new string, print that one too? Any boost library is fine - I have some experience with Fusion, but I don't know how it could automatically infer which members are strings.
C++ does not have any reflection. If you want to do this with macros, you would also have to define your member variables using specially crafted macros. A simple idea would be each macro would add the member to am internal vector and your printEm would just iterate through this vector. It's not the most elegant solution but it's how various libraries work.

C++ Combine enum and string into a map-like variable, able to be used with both int and string

Suppose I have an enum:
enum Types
{
TYPE_ASCENDING,
TYPE_DESCENDING
};
and I use it to it... anywhere in the code. Say if(bla < TYPE_ASCENDING), or with a switch/case. The real enum is much larger.
Whatever the results of the checks (or anything else), it needs to be std::cout in a prettier way to let the user know what happened. So, continuing the if() example, it might be something like this:
if(bla < TYPE_ASCENDING)
std::cout << "Ascending.\n";
All these happen inside a class. My question: is there a way to define some type of variable/STL/anything that would allow storing both enum-like and std::string-like variables, but would also let me use, separately, both types?
One thought was a namespace, but it seems it can't be used inside a class. To exemplify, here's what it would have looked like:
namespace Type
{
enum Types
{
ASCENDING,
DESCENDING
};
std::string s[2] {"Ascending", "Descending"};
};
and it would have been called as Type::ASCENDING for the if(), and Type::s[0] for the string. But, no namespace inside a class, so it's not a solution.
Using std::map only lets me use int as the index, so I can only use this:
std::map<Types, std::string> m {{TYPE_ASCENDING, "Ascending}, {TYPE_DESCENDING, "Descending"}};
as m[0], or m[TYPE_ASCENDING], but I can't call it for it's index to be used inside the if(). For that I have to call the enum, separately, which means I have both an enum and a map, two variables. I need one, unified, to avoid chasing variable names all over the code.
If I use a struct, I can't access directly Struct::TYPE_DESENDING, I need to create an object.
I can use an enum and a std::string array/vector, but that means that, again, I have to call two variables, separately, and I'd like them to be unified.
Is what I want possible?
You don't really have that mechanism in native C++. You can write a map / mapper function.
enum class E
{
ONE,
TWO
};
std::unordered_map<E,std::string> eStrings { {E::ONE,"ONE"},{E::TWO,"two"}};
While this is C++11 you can do the same for older C++ versions
Then you can use this like
std::cout << eStrings[E::ONE];
The issue here is you have to maintain this manually. So when you add a new value to the enum you have to manually add a new entry to the map.
The same would be true for writing a class or functions to have this behavior. You always have to duplicate the code of enum declaration and the mapping to the string.
A solution here would be to use some tool to generate these.
You can define in some file your enum (this is just some random format and only intended for explaining this. Chose whatever you want in your own defenition file)
E
- ONE
- TWO
And then generate the C++ enum and Map in a header and/or cpp file.
enum class <name>
{
<foreach:> <value>,
};
std::unordered_map< <name> ,std::string> eStrings
{
<foreach:> {<name>::<value>,"<value>"},
};
If you don't like having a map this approach is pretty flexible. You can also generate a switch case statement if you like
std::string getString(<name> e)
{
switch(e)
{
<foreach:> case <name>::<value>: return "<value>";
}
}
The syntax here is no standard for anything just some "pseudocode" to visualize the concept. There are several ways to generate c++ code out there. You can choose whatever you want or write your own program for this.
Note:
This is also just a general concept. You can wrap this functioniality / map etc into another class, make it static etc. for optimizations and not put it in global scope.
If you need something more fancy than just a map to lookup the string you can create a class with this concept or another map which does just the reverse lookup. It's more about the fact that you most likely have to generate the code by an external tool.
Reading Hayts answer I see that what I originally wrote may be relevant for the auto generation of code aspect. So I leave it here.
Seeing as regular old enums are implicitly convertible to int (as opposed to enum classes), you can simply use a map<int, string>.
Now, to the interesting part, generating it semi-automatically.
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}
I used a technique known as X-Macros. The premise is that you pass all the argument needed for your enum into the macro. Then you define the macro, depending on how you need the arguments to be used. So firstly:
# define ENUM_DEF(v, s) v,
This just expands the enum token as you'd provide it to a regular enum defintion.
Then, in Things c'tor:
# define ENUM_DEF(v, s) string[v] = s;
It expands to the statement you need to populate the map.
And to address one last point you may have issue with: Do you really have to do all this repetition, retyping ENUM_DEF all the time?
Well, luckily you don't. You can move those statements into their own file, let's call it type_enum.def:
#ifdef ENUM_DEF
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
#endif //ENUM_DEF
And the original code becomes:
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
# include "type_enum.def"
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
# include "type_enum.def"
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}

How to initialize and use an array of another class in a class? (C++)

So I am new to C++ and in Java, it was easy to use arrays of other classes and I was wondering if there was a way to use arrays of other classes like this:
#include <iostream>
#include <array>
#include <string>
using namespace std;
class Message
{...}
class UserMessageFile
{
private:
Message[] messages;
}
int main(int argc, const char * argv[])
{
return 0;
}
Why can't I use an array of the Message class in my UserMessageFile class? Do I need to include the Message class inside of the UserMessageFile class before I can do this? How exactly do I achieve this?
You cannot specify an array with unknown size as a class member (in fact you can't specify one unless it comes with a static initializer, and you can't have those in a class definition).
What you are looking for is std::vector.
class UserMessageFile
{
private:
std::vector<Message> messages;
};
You should almost always be looking to use std:: types. So use a std::vector or a std::array. If you really need to use a c style array you must do this:
Messages messages[10]; // Your syntax must have the array
// braces at the end and you must specify
// an array length.
Here is a live example.
Other syntax errors include:
Classes must end with a semicoln (class a {};).
Dont use ... in your class, this isn't recognized.

C++ : Using an array in a nested class definition (OOP)

So I am trying to define a class and I am using another array of a different class to define it.
//header file for Name.h
class Name {
string last;
string first;
};
//header file for Depositor.h
class Depositor {
Name name;
string ssn;};
//header file for Account.h
class Account {
Depositor depositor;
int acctnum;
string type;
double balance;
};
//header file for Bank.h
#include "Account.h"
class Bank {
Account account[]; //is this possible?
int active_accts;
};
When I am writing the cpp file I am running into a lot of problems!
//example of mutator
void Bank::setLastname(string lastname)
{
account.setLastname (lastname);
}
I didn't include the mutators and acessors that I wrote into the header file, but they are there and are public -- it won't compile.
Can you help? Is it even valid to use an array of a class in Bank.h?
Is it even valid to use an array of a class in Bank.h?
Yes, but it has to have a fixed dimension, e.g.,
Account account[3];
A type always has a fixed size in C++, and since an array member variable forms part of the class's size, you need to specify how many elements are in the array.
If you don't know how many elements you are going to need, you can use a sequence container:
std::vector<Account> account;
Account is not a nested class of Bank. Bank has a member data instance of type Account array.
You can have a primitive array member in a class, but you must specify the size of the array in the class definition: Account account[42];. The reason is that when you #include the class definition in another compilation unit, and then instantiate an instance of the class, the compiler needs to know what the size of that instance is.
It would be a wise idea to use std::vector<Account> rather than a primitive array. std::vector doesn't require committing to a particular size at construction; it grows dynamically. How come a std::vector doesn't require a size in the class definition, while a primitive array does? A std::vector holds as member a pointer to the elements on the heap. So the compiler does know the size of a std::vector; it uses the size of the pointer rather than the count of the elements.
By declaring the value of the array in the header file and by adding a variable in the .cpp file you can solve all the problems and leave it as an array.
//header file
class Bank {
Account account[100];
int active_accts;
public:
//mutator
void setLastname (string,int);
};
//the implementation file
void Bank::setLastname (string last, int index)
{
account[index].setLastname(last);
}
this will solve all your problems
account is an array of Accounts, which means you would need to do something like account[0].setLastname(lastname);
Instead of arrays, consider using vectors.
#include <vector>
// ...
class Bank {
std::vector<Account> accounts;
int active_accts;
};
you can't call setLastname(lastname) on the whole array. You need to call it on a specific instance of the Account class inside the array, like this: account[0].setLastname(lastname);
On another note, you really should be storing an array of pointers to Account objects.

Populate a static member container in c++

I've got a static class member which is some container, like
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
I need to populate the list with a number of specific values. Actually it should be also const, but that might overcomplicate the problem further.
All the class member functions are static, so initializing it in a constructor doesn't make sense.
a common solution is to do something like this:
// header
class Foo
{
...
private:
static list<string> s_List;
}
// cpp
list<string> init()
{
list<string> tmp;
... fill tmp with strings
return tmp;
}
list<string> Foo::s_List(init());
the other method is like Neil Butterworth suggested.
Another alternative is to create a simple initialiser class:
list <string> Foo::s_List;
struct Init {
Init() {
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
}
};
static Init doInit;
Note that, as the list is private, this will probably require you to make Init a friend of Foo. It's also often convenient to make such classes be contained by the class they are initialising.
However, I just re-read your question and another thought occurs - if the list is const, you will presumably not be changing it, in which case a simple array of strings, initialised with the strings in sorted order may be a better solution. It will certainly be faster to search (using std::binary_search) than a list, and can of course be easily initialised.
If your compiler supports C++0x, this is actually trivial to accomplish.
#include <iostream>
#include <list>
class Foo
{
public:
static std::list<std::string> s_List;
};
std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"};
int main()
{
for(const std::string& str : Foo::s_List)
std::cout << str << std::endl;
return 0;
}
This works for both const and non-const static members. I've tested this snippet with clang-4.2, gcc-4.7, gcc-4.6, and gcc-4.5. Gcc-4.5 does not support the updated for syntax, so you'd have to use a traditional for loop with iterators. Also, don't forget to pass the -std=c++0x flag to the compiler. I'm reasonably confident Visual Studio supports this as well, but I don't know for sure and don't know which versions.
It depends on what values you need to put in that list. Are they static or do they require some form of computation?
If they are static, you can do this:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
one possible solution would be to use an accessor method that checks to see if it is initialized, and does so if it isn't.
The ways I(the author of the question) have vainly tried to do this.
I tried to do smth like (in Foo.cpp):
list<string> Foo::s_List = list<string>();
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
But that gives a compiler error.
Then I thought of making an Initialize() method and calling it right from the code
void Foo::Initialize()
{
s_List.insert("rats");
s_List.insert("cats");
}
Foo::Initialize();
// error: compiler considers it to be a redefenition of the method, not a call.
The only viable idea left (havent yet tried) would be to check if the list is empty in each method that uses it, and if it's the case, call Initialize(). But that's ugly!