Is it possible to make a map class whose values are accessible with a dot-like notation?
I'd like to do something like this:
class Constants: std::map<std::string, float> {
Constant(std:string filename) {
/* Loads a key-value configuration file */
}
// Some magic here that lets me access
// the underlying map with Constants.alpha
// in addition to Constants["alpha"]
}
Constants C137("Dimesnion_C-137.txt");
Constants C131("Dimension_C-131.txt");
cout << C137["alpha"] << endl; // I can already do this
cout << C137.alpha << endl; // I'd like to do this
The code should behave literally as if whatever is written after the dot was into the string argument of the []-notation, that is C137.foo should behave exactly as if it was written C137["foo"], whether or not the underlying map contains the key.
The configuration file is comprised of a list of constants stored as key-value. Constants names are alphanumeric only, no spaces or special characters, and never begin with a number.
G 6.67430E-11
hbar 1.054571817E-34
alpha 7.2973525628E-3
...
I have many files, some of the constants are shared, but some are not (and many are in a single file only). Therefore I'd rule out the possibility of adding each constant as a class-member, because I simply would have too many of them. I decided to load them into a std::map<std::string, float> instead. If there was no way to do what I would like to do I would still use a std::map to hold the constants, and access them the usual way with the operator [].
The purpose of this is to avoid flooding my code with square brackets and strings:
Constants consts('constants.txt');
/* Write this */
mu_B = 0.5*const.electroncharge*const.hbar/const.electronmass;
/* Instead of this */
mu_B = 0.5*const["electroncharge"]*const["hbar"]/const["electronmass"];
I can achieve a similar result in Python:
class Constants(dict):
def __init__(self, filename):
# Load the file ...
pass
def __getattr__(self, attr):
return self[attr]
consts = Constants('constants.txt')
print(consts.alpha) # Equivalent to consts["alpha"]
You can't overload operator . so there is no way to do that to a map.
But is a map really the right structure anyway? From the examples it looks to me like you are defining some scientific constants and units. Not random user supplied config options. So all entries would be known at compile time and not change.
Sounds to me like a use case for https://en.cppreference.com/w/cpp/language/user_literal
If you define a bunch of user defined literals then
mu_B = 0.5*const["electroncharge"]*const["hbar"]/const["electronmass"];
becomes for example
mu_B = 0.5_ec * 1_hbar / 1_electronmass;
Related
I have a base class and I want to store instances of its derivatives in a collection of some sort.
At first I created a map:
std::map<int, Variable> varriableItems;
and then ussing templates I created functions for each derivative and I tried passing in the derivatives like so:
template <>
void Array::addToMap<Number>(Number input)
{
numberVariables[itemCount_] = input;
itemCount_++;
}
By doing so this function was not called because everything was of type Variable of course and I found out about slicing.
So instead I changed my map to take in pointers to my base class
std::map<int, Variable*> varriableItems;
but the problem I have is that all my objects are not created as pointers so I could not pass them in and I was getting errors.
No suitable conversion from "Number" to "Variable" exists.
Due to my implementation I can only create instances of objects
like so:
auto aNumberVariable = Number{50};
Ofcourse if I instead do:
Number aNumberVariable = new Number(50);
it works great.
The reason am doing this is explained bellow.
Please bear with me because this is a weird assignment.
We were asked to create a program that behaves/understands the syntax of a programming language called Logo, without actually analyzing the text as an input file, but rather "disguise" it to appear as such while in fact we just use C++ using what we learned from C++ and lots of overloads and pre-processor tricks
We have to be able to make our own "types" of variables called NUMBER,WORD,BOOLEAN,ARRAY, LIST,SENTENCE.
To declare them we have to use(note no semi-colons should be used):
//define number variable with value 21
MAKE number = NUMBER: 21
//define hello variable with value “hello”
MAKE hello = WORD: “hello”
//define myMoves variable contains list of turtle moves
MAKE myMoves = LIST [
LIST [WORD: “FORWARD”, NUMBER: 100],
LIST [WORD: “LEFT”, NUMBER: 90],
LIST [WORD: “FORWARD”, NUMBER: 100]
]
//define array variable with empty array
MAKE array = ARRAY {
number,
hello,
NUMBER: 12
BOOLEAN: TRUE,
ARRAY {
myMoves,
LIST [WORD: “BACK”, NUMBER: 100]
}
}
//define book variable with sentence type
MAKE book = SENTENCE (hello, WORD: “hello!”)
That's just a small part, we later have to support functions, nested loops , etc.
So do this I have to find a way to use the colon since I cannot overload it, so I did this:
//Create an instance of Number and write the first half of the ternary operator so we
//always get the false value so we can use the : like this
#define NUMBER Number{} = (false) ? 0
//semicolon infront for the previous command that needs it
#define MAKE ;auto
So now this:
//following commands will deal with the semicolon
MAKE myNumber = NUMBER: 21
worked great and it actually gets replaced by the processor to this:
auto myNumber = Number{} = (false) ? 0 : 21
So i worked with this for all my derivatives and I proceeded to overload operators to compare them, implement if else function in a similarly weird syntax.
Now I either have to figure out a way to make this work again but this time creating them as pointer instead (Which I assume is the only way for this to work, but I so far I couldn't figure it out) or create a single class for all types but doing it in separate objects that all inherit from a single base class makes more sense to me.
And am not sure how strict they will be, it is an unconventional project assignment for sure.
The reason I want to hold them together in a container is so I can then implement an Array and list object that can hold every type. At first I tried to use a different container for each type and made an iterator to iterate multiple maps separately, but when I got to the LIST implementation things got weird.
The list syntax is using the brackets [ ] which can only get 1 input value, so the idea was to collect them by overloading the comma operator and pass in one value to the list object.
I know this is weird , thank you for your time
I didn't read through all of your post. (actually I did because your task is so ... beyond words) but if you need polymorphism in a container and you also need the container to hold the objects, then the solution is unique_ptr:
container<std::unique_ptr<Base>>
In your case it would go something along this:
std::unordered_map<int, std::unique_ptr<Variable>> varriableItems;
varriableItems[0] = std::make_unique<Number>(50);
I want to store arbitrary parameter data for some robotics software. I'll give some examples to clarify what I want to do:
Say, for example, I want to store variables "quadruped.gait.step_height = 0.25" and "quadruped.gait.gait_type = "trot"" this should break down to something like
variable_map["quadruped"]["gait"]["step_height"] = 0.25;
or
variable_map["quadruped"]["gait"]["gait_type"] = "trot";
The code I currently have to handle this kind of thing (which works just fine if I know what the type of the variable is):
std::map<std::string, void* > var_map;
template <class X>
void set_variable(std::string key, X var)
{
var_map[key] = &var;
}
template <class X>
X get_variable(std::string key)
{
return *reinterpret_cast<X*>(var_map[key]);
}
this does the somewhat less clean looking task of storing each variable in:
variable_map["quadruped.gait.step_height"] = 0.25;
Which feels like a shoddy way of doing what I want. And I need to know the type of the variable ahead of time:
set_variable<bool>("quadruped.PID.workspace.active",true);
bool workspace_active = get_variable<bool>("quadruped.PID.workspace.active");
Ideally I'd like to handle this type of variable assignment in an XML reader or some kind of script-parsing format at startup.
I feel like this is a common need among software developers and I can't help but feel like I'm re-inventing the wheel on this problem. Is there a piece of open source code out there (preferably with a good license), or maybe just a simpler way of reading in a script:
quadruped.gait.gait_timing = [ 0 0.5 0 0.5 ]
quadruped.gait.step_height = 0.25
quadruped.gait.gait_type = "trot"
quadruped.PID.workspace.active = 1
and storing them as:
variable_map["quadruped"]["gait"]["gait_timing"] = (std::vector) % containing [ 0 0.5 0 0.5 ]
variable_map["quadruped"]["gait"]["step_height"] = (double) 0.25;
variable_map["quadruped"]["gait"]["gait_type"] = (std::string) "trot";
variable_map["quadruped"]["PID"]["workspace"]["active"] = (int) 1;
or maybe just storing them in any manner where I can retrieve them by name in my code such as in my previous example:
bool workspace_active = get_variable<bool>("quadruped.PID.workspace.active");
Thanks for your help. If you need any further clarification on any of the points I've made, I'll be monitoring this question closely.
Your problem is indeed a common problem. Therefore there exist a common solution, which is boost::variant that stores a variable of an arbitrary type.
The advantage is that it constructs the variant type based on all the potential types you consider (and provide as template parameters):
typedef boost::variant< int, std::string, double> vtype;
This approach permits to avoid common issues, like the nasty misaligned variables (see for example this SO question). It also enables some compile-time type checking, making sure that you don't use it accidentally types that are not foreseen.
vtype v1, v2;
v1 = "Hello";
v2 = 0.25;
cout << v1 << v2;
If you know the type stored in an object, you can get it very easily: instead of the risky *reinterpret_cast<X*> you would do: boost::get<X>()
And boost offers a visitation mecanism, to provide in an elegant manner the adequate type dependent code that it has to use for processing a variant objet. You'll find some nice examples in the link at the beginning of this answer.
Consider using Boost.PropertyTree, it implements the "hierarchical" map and also parsers to read configuration from files in some common formats. It stores the values by default in std::string format, but uses boost::lexical_cast to support setting and getting them in other types. If you want, you can use Boost.Any or Boost.Variant to store the values, but that would lose some parsing functionality.
header1.h
#define MaxNum 10
#define MinNum 1
//similar 100 other variables defined
main.cpp
#include header1.h
main()
{
int size;
string first = "MaxNum"; //could be any of the variable name defined in header file
size = MaxNum ;
I have certain variables defined in header file.
In main, depending on the value of "first" i need to set the value of "size". Is this do-able ?
I guess you want to have
size = MaxNum
if first == "MaxNum" and
size = MinNum
if first == "MinNum". If the set of possible values for first (the set of variables to choose from) is only small, you can simply put the assignment around an if, else if series of statements. Finally, put an else statement to write an error message.
However, you have to hardcode every case:
if (first == "MaxNum") {
size = MaxNum;
}
else if (first == "MinNum") {
size = MinNum;
}
//...
So your code to decide the assignment to size becomes larger as the number of variable grows. This is considered bad style and very unmaintainable as well as error-prone.
If you don't want to do this, don't use several variables in your program, but one container variable containing all these possible keys with their values. It's called associate container, and in C++ there is the type std::map which implements such a data structure.
// Your container for the sizes (or whatever you want to call it)
std::map<std::string, int> sizes;
sizes["MinNum"] = 1;
sizes["MaxNum"] = 100;
// ... more values ...
// Accessing this container with a variable as the key:
size = sizes[first];
As you can see, accessing this container using a string variable as the key is very easy. sizes[first] simply gives you the value in the container of which the key equals the value of the current contents of the variable first.
A very important fact about C++ (and C) source code is that during runtime you don't have access to the names of variables. So essentially, they can be renamed without affecting your program. What you want to have (querying names of variables, enums, classes, functions, their parameters, etc.) is known as introspection or meta-programming, as you write code which operates on your code ("meta-code").
C++ doesn't provide meta-programming facilities per default (only exception I know of: typeid, but nothing for variable names / defines). By default means, that you could hack around this limitation and include some additional step in your build process which parses your header file for these definitions and stores them in a different way accessible during runtime. But the map is the better way, believe me.
I have the following chars to whom I want to assign numbers consecutively if they are in the same bracket. E.g.
[a,b],[c],[d,e],[f,g],[h]
a=0, b=1,c=2,d=3,e=4,f=5,g=6,h=7
From the given char I want to retrieve the number which I can do with std::map in c++. However, once i assign these numbers with map. I loose the information that [a,b] are in one bracket and [c] is separate. This information I want to retain.
Is there some data structure which I can use such that: [a,b] can be assigned consecutive numbers and also I can get the information that [a,b] are in one bracket and [c] is the only ones in its bracket.
My approach was to use map...but it does not fit my need of later finding out whether [a,b] are in the same bracket. Can someone please suggest a data structure such that it satisfies my need of assigning numbers consecutively as well as retaining the information that they belong to the same bracket.
It's not entirely clear to me what you are asking, but this answer is based on my current interpretation. Can't you just use a value type that stores the extra information about what group the char is in? For example:
struct value_type
{
int num;
int group;
};
....
std::map<char, value_type> m;
m['a'].num = 0;
m['a'].group = 0;
m['b'].num = 1;
m['b'].group = 0; // same group as 'a'
m['c'].num = 2;
m['c'].group = 1; // new group
// etc...
// testing if 'a' and 'b' are in the same group
if (m['a'].group == m['b'].group)
...
As others pointed out, there is no data structure that fits your needs perfectly (as far as I know). You can, however, easily design one yourself. Some suggestions:
Map each character to a tuple or struct that contains the bracket number and the character number:
struct CharData { int group; int characterNumber; };
std::map<char, CharData> data;
Use two containers: One contains a list of character groups / brackets, the other one is a plain map:
std::vector<std::vector<char> > groups; // Store groups in this container.
std::map<char, int> mapping; // Store mapping to integers in this container.
Use a vector of maps:
std::vector<std::map<char, int> > data;
You can easily convert between these representations. They have different complexity for typical operations though. If it is important to you that you can check if a character is in a certain group and to access the number it is mapped to, then go four the first solution. If you need to list all characters of a group quite often or a character can be contained in multiple groups, then I would prefer the second approach. The last approach can be useful, if a character can be an element of multiple groups and you want to map it to different numbers depending on the group.
How do you make a variable name where you create a variable and then in brackets the variable number? (By the way, I'm just guessing out how the code should be so that you get what I'm trying to say.) For example:
int var[5];
//create a variable var[5], but not var[4], var[3], var[2], etc.
Then, the variable number must be able to be accessed by a variable value:
int number = 5;
int var[number]; //creates a var[5], not a var[4], etc.
int var[2]; //creates a var[2], not a var[1], etc.
cout >>var[number];
number = 2;
cin << var[number];
If I'm way off track with my "example", please suggest something else. I need something similar to this for my game to operate, because I must be able to create an unlimited instance of bullets, but they will also be destroyed at one point.
It looks like you are looking for the functionality provided by std::map which is a container used to map keys to values.
Documentation of std::map
Example use
In the below example we bind the value 123 to the integer key 4, and the value 321 to key 8. We then use a std::map<int,int>::const_iterator to iterate over the key/value pairs in our std::map named m.
#include <map>
...
std::map<int, int> m;
m[4] = 123;
m[8] = 321;
for (std::map<int, int>::const_iterator cit = m.begin (); cit != m.end (); ++cit)
std::cout << cit->first << " -> " << cit->second << std::endl;
output:
4 -> 123
8 -> 321
It looks like you want variable length arrays, which is not something C++ supports. In most cases, the correct solution is to use an std::vector instead, as in
int number = 42; // or whatever
std::vector<int> var(number);
You can use std::vector as you would use an array in most cases, and you gain a lot of bonus functionality.
If I understand what you want correctly (which I'm not certain that I do), you want to be able to create a place to hold objects and use them according to some index number, but to only create the specific objects which go in it on demand. You want do to this either because 1) you don't know how many objects you're going to create or 2) you aren't going to use every index number or 3) both.
If (1) then you should probably just use a vector, which is an array-like structure which grows automatically as you add more things to it. Look up std::vector.
If (2) then you could use an array of pointers and initially set all of the values to null and then use new to create the objects as needed. (Or you could use the solution recommend in part 3.)
If (3) then you want to use some form of map or hash table. These structures will let you find things by number even when not all numbers are in use and will grow as needed. I would highly recommend a hash table, but in C++, there isn't one in the STL, so you have to build your own or find one in a third-party library. For ease, you can use std::map, which is part of the STL. It does basically the same thing, but is slower. Some C++ distributions also include std::hash_map. If it's available, that should be used instead because it will be faster than std::map.