Adressing variables by variable names [duplicate] - c++

This question already has answers here:
Iterate through Struct and Class Members [duplicate]
(6 answers)
Closed 2 years ago.
I am currently writing a ROS 2 node to pass values from a PLC through ROS to a visualization:
PLC System --> ROS --> Visualization
Since ROS should only pass on the data, I want to be able to configure the interface here with as little effort as possible. The idea, which can be implemented best with ROS, would be a config-file(.msg file), in which the designation of the variables and their type is entered. Everything else is then derived from this.
The problem I inevitably run into with this: In ROS data are passed on over so-called messages. These messages are defined via structs and are automatically generated from my config-file. To assign values to the variables from the struct, I don't want to address every single one hardcoded in the program, but rather iterate through the struct using the known names.
TLNR: Can variables be addressed with variable variable names?
I know that the whole thing sounds a bit confusing. I hope the following example will clarify what I mean:
#include <vector>
#include <string>
struct MsgFile
{
int someVariable;
int someOtherVariable;
};
using namespace std;
class Example
{
public:
vector<string> variableNames{"someVariable", "someOtherVariable"};
MsgFile message;
void WriteVariables()
{
for (auto const &varName : variableNames)
{
message."varName" = 0; //<-- pseudo code of what I'm thinking of
}
}
};
Regards
Tillman

You cannot use variable names like that. There are no variable names at runtime. If you want a mapping between names (strings) and variables, you need to add that yourself.
If your "variables" are of same type, eg int, you can use a map:
#include <vector>
#include <string>
#include <unordered_map>
using MsgFile = std::unordered_map<std::string,int>;
struct Example {
std::vector<std::string> variableNames{"someVariable", "someOtherVariable"};
MsgFile message;
void WriteVariables() {
for (auto const &varName : variableNames) {
message[varName] = 0; // add an entry { varName, 0 } to the map
// (or updates then entry for key==varName when it already existed)
}
}
};
If you only need the string representation to access it (but not for printing etc) you can consider to use an enum as key instead. At least I'd define some constants like const std::string some_variable{"some_variable"}, to avoid typos going unnoticed (perhaps the variableNames is supposed to be const (and static?)).

As far as I know there is no standard way to do this, I would choose another way to store the data ( I mean not in struct ), but if you are adamant here is an answered question:
Get list of C structure members

Related

How can i access variables in the main function from other function [duplicate]

This question already has answers here:
access variables from other function c++
(4 answers)
Closed 1 year ago.
I've looked at other topics, the answers usually solve the problem using parameters, but this is not the way I want. I'm new to C++, I was developing NodeJS before. Can we make a variable that we can access from the region we want like in NodeJS?
string read_from_ram(string& key) {
//how can I access and edit keysDB and valuesDB variables from here
}
int main(int argc, char* argv[]) {
auto [keysDB, valuesDB] = read_from_disk();
}
No. You'll have to pass a pointer/reference to the function with the way you currently have it written, or set it as a global variable (which is typically frowned upon unless required by the problem scope).
Another potential idea would be to make an object.
class MyClass {
private:
string key;
public:
string read_from_ram(string& key) {};
};
In this case, key would be accessible from anywhere inside your class.
You have to pass those variables to your function. That's something every textbook would have told you in the very first chapters.
Guessing the types, this could be what you want:
std::string read_from_ram(const std::string& key,
const std::vector<std::string>& keys,
const std::vector<std::string>& values)
{
// access keys and values here
}
int main(int argc, char* argv[])
{
auto [keysDB, valuesDB] = read_from_disk();
auto foo = read_from_ram("foo", keysDB, valuesDB);
}
You could also make them global, but that would probably be a bad design choice.
If I understand you correctly, then you want to access a variable globally. If that is the case than you just have to define a global variable, which means define a variable outside of all functions, usually this is done under your includes. Warning: Usually you should avoid global variables because they can be manipulated from anywhere in the program and generic names can also be dangerous.

define list in header vertice on c++

I have problem with define syntax of List this error that I getting, I tried creating a list of Vertice and I have problem with the syntax, I tried using namespace STD also in a header but still getting an error:
Severity Code Description Project File Line Suppression State
Error (active) E0415 no suitable constructor exists to convert from "std::list> *" to "std::list>" graf C:\Users\danie\OneDrive\Desktop\graf\graf\Vertice.cpp 39
Vertice.h
#pragma once
#include <list>
#include <iostream>
class Vertice {
std::list<Vertice> getList();
void setList(Vertice v);
private:
std::list<Vertice> *N;
};
Vertice.cpp
#pragma once
#include <list>
#include <iostream>
#include "Vertice.h"
using namespace std;
Vertice::Vertice(int b, int f) {
N = new list < Vertice > ();
color = 0;
}
list < Vertice > Vertice::getList() {
return N;
}
void Vertice::setList(Vertice v) {
this - > N - > push_front(v);
}
Vertice::~Vertice() {
N - > clear();
}
The reason why you are getting comments and not answers is because you
a) Did not post the error message (as mentioned in a comment)
b) Your code contains many errors and some anti-patterns.
When using namespaces in C++ the convention is to use the full namespace in header
std::list<Vertice> *N; // member declaration
and a "using" declaration in the module.
using namespace std;
...
list<Vertice> Vertice::getList() const // return by value, mark as const
{
return N; // you don't need this->N in C++
}
However, many people prefer to simply type the full namespace always, so if you find this easier to understand, try using that.
What are you trying to achieve with this code? The reason I ask is because dynamically allocating a "std::list" is a bit weird. A "std::list" is designed to manage memory for you, which makes this code read a bit like "allocate a pointer to hold the address of the memory I'm about to allocate". I strongly suspect you are trying to make a recursive structure (a tree). Surprisingly C++ does not require you to use pointers to do this (C does). Maybe this pattern will help?
class NTree
{
private:
std::list<NTree> children;
};
I would suggest you get your code working like that first. If need to optimize, you will more control of the memory, then something like this will help.
class NTree
{
private:
std::vector<std::unique_ptr<NTree>> children;
};
This will allow you to, for example, move a child from one node (NTree) to another (NTree - or other), in a safe way. This avoids any copying overhead. This is a minor saving unless either your trees get very big or they contain objects which are very big. Even expert C++ programmers will try and get their code working before trying an optimization like this. There is no way to predict if it will required or not, so as always benchmark before and after.

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;
}

Call obejct and method via variable (string) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
First of all, I have been looking on stackoverflow for more than 1 hour, but I really don't know, how to find the specific question I'm looking for (I guess there is already some answer).
I am trying to call an object via variable (string)
example of my code:
//class itself
using namespace std
class locations {
public:
locations(int id, string name){ // constructor
this->id= id;
this->name=name;
}
int id= 0;
string name = "";
};
and new object:
locations home(1,"home");
what I want now is something like:
string obj = "home";
obj.id = 3;
or
string meth = "id";
home.meth = 3;
If you have any good links to other questions it would be helpful.
Maybe it can be accessed somehow through vectors but I don't know about it a lot
C++ is designed with strong typing and compile time checking and optimization in mind. There's no build in facilities for the kind of access that you desire.
1) Find dynamically an object:
C++ doesn't support the semantic that you expect:
string obj = "home"; // create an object of type string.
obj.id = 3; // access to member id of your object.
If it would be dynamic, the generated code would need to maintain the scope of variables (because the home object can have different meansings in different scope.
But fortunately you can easily implement an object store, in wich you register your objects and their name, with the help of a map :
map<string, locations> mystore; // store of all my location variables
mystore["home"] = locations(1,"home"); // copy a new object into the store
string obj = "home";
mystore[obj].id = 3; // access object via its name.
By the way, if locations::name is only there to give access by name, you'd no longer need it in locations, as the map links the string to the object value anyway.
2) Find dynamically a member:
C++ doesn't support your semantic at all:
string meth = "id"; // name of a member
home.meth = 3; // invalid: because meth is not a member of home
C++ doesn't support reflection that you find in java and other semi-compiled or interpreted languages. If you need something like that, you'd need to design carefully your classes to implement this by yourself. It'll be rather difficult as every member can have its own type, and C++ needs to know the type at compile time.
One way would be to combine the use of a map (to store your dynamic members) with the use of boost::variant (to store in the map objects that can have different type of values).
But it's not easy, and most of all, you'd have to manage by yourself any inheritance logic betwwen diferent classes.
This isn't how thing are done in C++, C++ is a object oriented, statically typed, value semantics language. All of these affect design, and the design you seem want just don't fit with a statically typed language. Whether this lead you to change design, or change language is up to you. That said, if you really want to map objects and methods runtime, it could be emulated something like this:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct Object;
typedef int (*funcptr)(Object*,int);
struct Object
{
map<string,funcptr> funcs;
map<string,int> data;
int call(string name,int param) { return funcs[name](this,param); }
};
map<string,Object> allObjects;
Object& get(string name) { return allObjects[name]; }
//----------------------------------------------------------------------------------
int main()
{
get("obj1").funcs["run"] = [](Object* self,int param) -> int { self->data["somename"] = param; return 0; };
get("obj1").call("run",5);
cout << get("obj1").data["somename"] << endl;
}
That said, please don't do that, change your design to something that actually is a good fit for C++'s strengths, i.e. object oriented, statically typed, value semantics.