Using variables as part of a variable reference [duplicate] - c++

This question already has answers here:
Is it possible to use dynamic name for variables in c++
(5 answers)
Is it possible to build variable name at runtime in C++? [duplicate]
(2 answers)
Create sequential variable names using a loop in C++
(4 answers)
Convert string to variable name or variable type
(7 answers)
How to input the name of a variable and use the variable in a function in c++? [duplicate]
(3 answers)
Closed 27 days ago.
Pretty simple c++ question here, how do I replace part of variable reference with another variable, almost to concatenate it.
For example I have a structure with item1, item2, item3, I ask the user what Item they want the information of which is stored in a variable itemNo for example:
cout << "The item you selected is " << item(itemNo).name;
if itemNo==1 the reference would need to become item1.name;
Brackets is wrong in this scenario, but what is the right way to insert a number to form the right variable reference?

As mentioned in comments, if you name member item1,item2, item3,etc then you rather want a std::array, or if the number of items is dynamic then std::vector. Once you use a container as member, the container does provide a means of element access. However, as you are asking for it, it follows a way to make items(itemNo).name work. It makes use of operator overloading. And it uses a vector to store the data.
#include <string>
#include <vector>
#include <iostream>
struct Item { std::string name = "name";};
struct Items {
std::vector<Item> data = std::vector<Item>(10);
Item& operator()(size_t i) { return data[i];}
const Item& operator()(size_t i) const { return data[i];}
};
int main() {
Items items;
items(5).name = "Hallo";
std::cout << items(0).name << " " << items(5).name;
}
For further reading I refer you to operators#cppreference and What are the basic rules and idioms for operator overloading?. For the containers container#cppreference, std::array, and std::vector.

You can define struct as a holder for your item
struct item {
std::string name;
}
and then you can store items in array.
#include <array>
#include <string>
#include <iostream>
struct item {
std::string name;
};
int main() {
std::array<item, 3> items{ {{.name = "item1"}, {.name = "item2"}, {.name = "item3"}}};
item& current_item = items[0];
std::size_t chosen{0};
std::cout << "choose item (1-3):\n";
std::cin >> chosen;
current_item = items[chosen];
std::cout << "current item: " << current_item.name << "\n";
}
You can switch to std::vector if you want to store dynamic number of elements.

Related

Accommodation for dynamic array

From this discussion, I have the following code to check if an element exists in an array:
#include <iostream>
#include <vector>
template <typename T, std::size_t N>
bool IsIn(T value, const T(&values)[N])
{
for (const T& array_value : values)
{
if (value == array_value) return true;
}
return false;
}
int main() {
int arr1[] = { 10, 20, 30 };
bool ee1 = IsIn(10, arr1);
std::cout << "ee1 = " << (ee1?"true":"false") << "\n";
return 0;
}
I believe this code is good for array of fixed size (at compile time) only. If the array is dynamically created (the number of elements is not known at compile time), is there any way I can modify the code to accommodate it?
PS: I am aware of vector. However, I am just curious if there is any way to avoid it.
Don't use C-style arrays unless you absolutely need to. Use std::array instead. For dynamic arrays, use std::vector.
You can then use iterators to make your function generic. However, this function already exists, it's called std::find. You can try to implement your own, for learning purposes, or look up an example implementation here: cppreference | find
#include <algorithm>
#include <array>
#include <iostream>
#include <string>
#include <vector>
int main(){
std::array<int, 3> static_array{1, 2, 3};
std::vector<int> dynamic_array{3, 4, 5};
std::string str = "Hello World";
std::array<int, 3>::iterator stat_found;
if( (stat_found = std::find(static_array.begin(), static_array.end(), 3)) != static_array.end() ){
std::cout << "Found 3 in static_array at pos: " << stat_found - static_array.begin() << "\n";
}
std::vector<int>::iterator dyn_found;
if( (dyn_found = std::find(dynamic_array.begin(), dynamic_array.end(), 3)) != dynamic_array.end() ){
std::cout << "Found 3 in dynamic_array at pos: " << dyn_found - dynamic_array.begin() << "\n";
}
std::string::iterator str_found;
if( (str_found = std::find(str.begin(), str.end(), 'W')) != str.end() ){
std::cout << "Found W in string at pos: " << str_found - str.begin() << "\n";
}
}
Without changing the body of your method, you can accommodate practically any collection type by abstracting over the collection type as well, i.e.
template <typename T, typename Collection>
bool IsIn(T value, const Collection &values)
{
/* ... */
}
However, as inifnitezero noted, the standard way of doing this is actually with iterators, and many implementations already exist in the standard library for this.
For a dynamic array you have to pass in the size in some form or another.
template <typename T>
bool IsIn(T value, const T *arr, std::size_t size) { ... }
You already know about std::vector, which knows it's own size, so I will skip that. That is the way to handle dynamic arrays. But not the only way to pass them to a function.
You can use std::span, which can be used for fixed sized arrays, std::array, std::vector and any container with random access iterator (sequential iterator? not sure). It's probably the most flexible thing to use.
You can also use begin and end const iterators. But that involves a lot of typing unless you already have 2 iterators when you want to call it.
Personally I think std::span covers all the bases. You can even make a span from iterators.

python-style function list input for c++

I want to have an input to a function similar to python so that then I can loop over it in inside the function. But I am not sure how I should define the input.
func(["a","b","c"])
so that it can also be called
func(["a","b","c", "d"])
is there actually such style of input in c++?
I'd be glad if someone also suggested a way of looping over it since my c++ experience is quite basic.
-------edit,
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Yes, you can use std::initializer_list to do that:
#include <initializer_list>
template<class T>
void func(std::initializer_list<T> il) {
for (auto x : il);
}
int main() {
func({"a","b","c"});
func({"a","b","c", "d"});
}
will be glad if this "[]" style of brackets are possible instead of
"{}" similar to python and with minimal code.
Unfortunately, the multidimensional subscript operator only works in C++23, see p2128 for more details.
You can use a std::initilializer_list:
#include <iostream>
#include <initializer_list>
void foo(std::initializer_list<std::string> l){
for (const auto& s : l) std::cout << s << " ";
}
int main() {
foo({"a","b","c"});
}
I think python does not distinguish between character and string literals, but C++ does. "a" is a string literal, while 'a' is a character literal. If you actually wanted characters you can use a std::initializer_list<char>. You can also consider to simply pass a std::string to the function (foo("abc")).
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Better get used to different languages being different. Trying to make code in one language look like a different language usually does not pay off, because not only in details python and C++ are very different.
The other answers will work but I think your looking for std::vector, which is a array that can dynamically grow and shrink. It is basically the c++ equivalent to a python list (except you can only store on data type in it).
#include <iostream>
#include <vector>
void foo (std::vector<std::string> vec)
{
// normal for loop
for (int i = 0; i < vec.size (); i++)
{
std::cout << vec[i] << std::endl; // do something
}
std::cout << "#########" << std::endl;
// range based for loop
for (auto val : vec)
{
std::cout << val << std::endl;
}
std::cout << "#########" << std::endl;
}
int main ()
{
foo ({'a', 'b', 'c'});
foo ({'a', 'b', 'c', 'd'});
}
replace std::string with the data type that you need.
live example
I would recommend you to use std::initializer_list for that purpose.
The function may be defined as follows:
void func(std::initializer_list<std::string> il)
{
for(const std::string & s : il)
{
// ...
}
}
And you may use it the following way:
int main()
{
func({"a", "b", "c"});
return 0;
}
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Python and C++ are not the same languages and symbols, keywords, etc... have their own meaning. In Python, [] means a list, but in C++ it is the subscript operator (supposed to be called for a given object), which is a completely different thing.

C++ Create array with dynamic name

I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?
If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.

Vector for loop isn't working:: vector subscript out of range [duplicate]

This question already has answers here:
When I change a parameter inside a function, does it change for the caller, too?
(4 answers)
Closed 5 years ago.
The goal here == i'm trying to push_back a string value into a vector.... issues arises such as (vector subscript out of range)
i've made a function that accepts a string vector as a parameter
i've made a for loop inside that function utilizing a variable combined with a 'cin' function
all i got back is 'vector subscript out of range'... how? am i missing something?
#include <iostream>
#include <vector>
#include <string>
void sentDef(std::vector <std::string> sentienceVar) {
std::string terms;
std::cout << "input how many terms/variables made" << std::endl;
int howManyVar;
std::cin >> howManyVar;
for (int i = 0; i < howManyVar; i++) {
std::cin >> terms;
sentienceVar.push_back(terms);
}
}
int main() {
std::vector <std::string> sentienceVar;
sentDef(sentienceVar);
std::cout << sentienceVar[0] << std::endl;
system("pause");
}
Change this:
void sentDef(std::vector <std::string> sentienceVar)
to this:
void sentDef(std::vector <std::string>& sentienceVar)
Now your vector is passed by reference, and thus preserves the changes made to it.
In your code, it was passed by value (thus a copy of it was passed to the function. The function operated on that copy, and at the end of that function, that copy went out of scope).
To expand on #gsamars, please google passing arguments by copy and by reference.
What you are doing in your function is accepting a copy of the vector, so the original sentiencevar is empty when the function returns!
The addition of & after the type tells the compiler you want to pass by reference, so what you coin the function affects the original vector. Note this is also faster than creating a copy.

What is the curly bracket parameter in the constructor of C++11 [duplicate]

This question already has answers here:
C++11 Fun with initializer lists, arrays, and enumerations
(5 answers)
Closed 9 years ago.
I read an implementation of a Queue from some algorithm books, there is a snippet that is new/interesting to me which I didn't understand. I think it is something new like initialization list for vector in C++11, but I am not that confident due to the context of the code. Can anyone shed a light or provide some reference?
template <typename T>
class Queue {
private:
size_t head, tail, count;
vector<T> data;
public:
Queue(const size_t &cap=8) : head(0),tail(0),count(0),data({cap}) {}
//... more interfaces
//...
}
the questionable part is data({cap}), what is this? It resizes the vector to a capacity of cap? (Obviously the author of the code intends to give data a size of cap when constructing it.)
EDIT:
after read the first answer and test, we know that the book had error in the snippet. It intends to give a initial cap, but it used erroneous {}.
That is uniform initialization, a new C++11 feature. However, it is arguably being used the right way in your example. It should be:
Queue(const size_t &cap=8) : head(0),tail(0),count(0),data(cap) {}
// ^^^^^
Because the intention is to invoke the constructor of std::vector<> that accepts the initial size of the vector. Invoking it this way:
data{cap}
Or this way:
data({cap})
Causes the constructor accepting an std::initializer_list to be picked (initializer lists are another new feature of C++11, tightly related to brace initialization), resulting in a vector initialized with one single element whose value is cap.
You can verify the above claim in this live example (code is reported below):
#include <vector>
struct X
{
X(int s) : v1({s}), v2{s}, v3(s) { }
std::vector<int> v1;
std::vector<int> v2;
std::vector<int> v3;
};
#include <iostream>
int main()
{
X x(42);
std::cout << x.v1.size() << std::endl; // Prints 1
std::cout << x.v2.size() << std::endl; // Prints 1
std::cout << x.v3.size() << std::endl; // Prints 42
}