set variable depending on other variable - c++

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.

Related

Access C++ map with dot syntax

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;

Any straightforward way to capture and initialize multiple return values from function

In my project there are few functions that return multiple values with the help of tuple and they are used numerously. So I just want to know is there any way in c++ with which I can capture and initialize individual values that are returned by that function call. Below example will explain this question better
#include <iostream>
#include <string>
#include <tuple>
std::tuple<std::string,int,int> getStringWithSizeAndCapacity()
{
std::string ret = "Hello World !";
return make_tuple(ret,ret.size(),ret.capacity());
}
int main()
{
//First We have to declare variable
std::string s;
int sz,cpcty;
//Then we have to use tie to intialize them with return of function call
tie(s,sz,cpcty) = getStringWithSizeAndCapacity();
std::cout<<s<<" "<<sz<<" "<<cpcty<<std::endl;
//Is there a way in which I can directly get these variables filled from function call
//I don't want to take result in std::tuple because get<0>,get<1> etc. decreases readibility
//Also if I take return value in tuple and then store that in individual variables then I am wasting
//tuple as it will not be used in code
return 0;
}
Is there a way in which I can directly get these variables filled from function call I don't want to take result in std::tuple because get<0>,get<1> etc. decreases readibility
Also if I take return value in tuple and then store that in individual variables then I am wasting tuple as it will not be used in code
I understand that the use of std::get<>() decreases readability, but you can try to improve it with some comments
// get the size of the returned string (position 1)
auto sz = std::get<1>(getStringWithSizeAndCapacity());
Anyway, it seems to me that the right way to improve readability is the use of std::tie(), and isn't clear to me what's wrong with it for you, or (starting from C++17) also structured binding declarations
auto [ s, sz, cpcty ] = getStringWithSizeAndCapacity();
If you want avoid to name unused variables (say you are not interested in capacity, by example) you can use std::ignore
std::string s;
int sz;
std::tie(s,sz,std::ignore) = getStringWithSizeAndCapacity();
Unfortunately std::ignore can't be used (as far I know) with new C++17 structured binding (maybe something similar from C++20?).

Efficient way to declare and access a huge array

I am writing a code for which I need to declare an array of around 200 indexes. Now to search a specific index I at least need to travel the array for a defined time or until desired value is achieved - hence at times I might need to travel 200 times if needed - for 200 value row.
This is exactly I wish to ignore so I landed coding it below way:
enum Index{ salary, age };
static const Datas Mydata [] =
{
[Index::one] = {"hello", function_call_ptr_1, function_call_ptr_2},
[Index::two] = "hekllo1", function_call_ptr_1, function_call_ptr_2}
};
Hence in my code I can directly seek it like below:
Mydata [Index::age]
Assuming that access to above structure is to be done inside a function - hence the function should receive Index value as argument to itself. But still what if arguments passed was wrong like:
age = 0;
fun(age);
Is there a better way to access Mydata so that its desired row can easily be accessed without any flaw?

Heterogeneous container of base class when the derived instances are not pointers

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

How to make a variable name without creating an array in C++?

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.