assign values to member of a struct with a for loop - c++

I have a struct of the form
struct Thing {
std::vector<bool> A;
std::vector<int> B;
};
in the main the struct is created inside a for loop and used as the input to a function
for(int i=0;i<50;i++) {
Thing temporalthing;
temporalthing.A=A;
temporalthing.B=B;
temporalresult=fun1(temporalthing,data)
}
A and B are hardcoded into a series of vectors stored like this
std::vector<bool> A1{ 1,0,1};
std::vector<int> B1{ 2,1,3};
std::vector<bool> A2{ 0,1,1};
std::vector<int> B2{ 4,2,3}; ....
I want for each iteration of the for loop to take the corresponding value of A and B (loop 1 take A1 and B1, loop 2 take A2 and B2, ETC), if this were MATLAB this would be easy using reflection but I understand C++ does not have reflection, my other option would be to use a Switch Case structure of 50 different values that surely would work but I am not sure if this is the most optimal way to do it. Is there a better way?
I am new to C++ having a lot more experience with MATLAB but trying to learn... any help is very appreciated

My suggestion:
Change
temporalthing.A=A;
temporalthing.B=B;
to
temporalthing.A = getA(i);
temporalthing.B = getB(i);
The functions getA() and getB() can use whatever logic to return you an A and a B for the given i.
A simple implementation for getA() would be to store the various As in a vector.
std::vector<int>& getA(size_t i)
{
static std::vector<std::vector<int>> aList;
if ( aList.empty() )
{
// Fill up the list
aList[0] = {1, 0, 1};
aList[1] = {0, 1, 1};
// etc.
}
return aList[i];
}
Do the same thing for getB().
If getA() can use i to compute the return value, then, it does not have to store the As.
std::vector<int> getA(size_t i)
{
int v1 = func1(i);
int v2 = func2(i);
int v3 = func3(i);
return {v1, v2, v3};
}

Related

Initializing some elements of vector of defined size

Is there a way to initialize first few elements of a vector after defining the size of the vector like -
vector<int> vec (10);
This doesn't work and produces a compiler error -
vector<int> vec(10) {1,2,3};
For example with arrays we can do the same thing like -
int arr[5] {1,2,3}; // This will initialize the first 3 elements of the array to 1,2,3 and the remaining two to 0.
In short, no. Your can fill out the entire list of things you want to be in the vector:
vector<int> vec{1, 2, 3, 0, 0, 0, 0, 0, 0, 0};
Which will give you a vector of 10 elements.
Or, you can create the vector, then call resize to make it larger (filling the remaining elements with 0):
vector<int> vec{1, 2, 3};
vec.resize(10);
You generally don't need to do this kind of thing to vector though, because unlike array, you can extend vector as needed, after creation:
vector<int> vec{1, 2, 3};
vec.push_back(4);
There isn't a way to do it all in one line like you can with an array. You can use
vector<int> vec{1,2,3};
vec.resize(10);
but that does make the code a little less easy to use. Another option is to wrap that in a function like
template <typename T>
auto make_sized_vector(std::intializer_list<T> il, std::size_t size = 0)
{
const auto vec_size = std::max(size, il.size());
vector<T> vec; // create vector
vec.reserve(vec_size); // allocate all the storage needed
vec.assign(il); // assign the elements
vec.resize(vec_size); // set the rest to zero
return vec;
}
and then you can use that like
auto vec = make_sized_vector<int>({1, 2, 3}, 10);
If you are concerned about passing the std::intializer_list by value see why is `std::initializer_list` often passed by value? for why that really isn't a concern.
In case you want to initialize a vector the way you describe, all at once, so that it can become (e.g.) a const member, this is always possible in C++, with just a bit of ugliness and twisting. Let’s say you have a class:
struct SomeClass {
SomeClass(const std::vector<int> &start, int rest, std::size_t size);
const std::vector<int> some_vector_; // This is const!
};
What the constructor could look like:
SomeClass::SomeClass(const std::vector<int> &start, int rest, std::size_t size)
: some_vector_{[&start, rest, size] {
std::vector<int> some_vector;
some_vector.reserve(size);
some_vector.insert(some_vector.end(), start.begin(), start.end());
some_vector.insert(some_vector.end(), size - start.size(), rest);
return some_vector;
}()} {}
Basically the problem boils down to: How do I do “something procedural” in an initializer list? To which the answer is: You invoke a function that returns the desired type.
To test the construct above:
#include <cstdint>
#include <iostream>
#include <vector>
namespace { /* SomeClass stuff from above goes here. */ }
int main() {
SomeClass sc{{1, 2, 3}, 0, 10};
for (int i : sc.some_vector_) std::cout << i << '\n';
}
There are (of course) plenty of ways to make it (slightly) more efficient if needed, such as
a templated variadic constructor to create the initial part of the vector,
a templated perfect-forwarding constructor to benefit from R-value containers, and
as a combined benefit of the above, arbitrary iterable containers as inputs and as the const member.

referencing a global vector by a different name within a function

suppose you have three global vectors V1, V2, and V3.
suppose you have a function which performs a set of actions, such as VN[3]++, on one of the above vectors determined by an int value.
in python i would do something like:
global:
v1 = [1,2,3]
v2 = [1,2,3]
v3 = [1,2,3]
lists = [v1, v2, v3]
def function (determiner):
list = lists[determiner]
list[1] += 1...
I think in theory i could just have separate ifs for each possible value of determiner, but it seems like bad code to repeat a length of code multiple times.
(1) What is the correct way to approach this problem? I assume I would use pointers, but I've just learned about them today and i've been struggling to get my code to work. Here's a sample of the code i've been trying.
vector <int> counts0;
vector <int> counts1;
void editor(int determiner){
if (determiner == 1) {
vector<int> & count_l = counts1;
}
else if (determiner = 2) {
vector<int> & count_l = counts2;
}
count_l[5]++;
}
There are two ways to achieve this, depending on what you expect. If lists should reference the vectors, use pointers (as you said, just remember to dereference before indexing)
std::vector<int> a, b, c;
std::vector<std::vector<int>*> lists = {&a, &b, &c};
void editor(int determiner)
{
(*lists[determiner])[5]++;
}
If you want a copy of all vectors in list, don't use pointers (this can be expensive when you modify lists a lot, only use this approach with const data).
std::vector<std::vector<int>> lists = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}};
void editor(int determiner)
{
lists[determiner][5]++;
}

C++ std::valarray member variable unexpected change

I have a class A whose constructor takes as one of its arguments as an std::valarray[^1], however I have found that its values change to large random numbers once the constructor has finished.
As an aside, there could be an issue with my getters and setters, which I just started using in the cotext of C++ with the help of this SO question and 18.3.5 Accessor Functions from Stroustrup's The C++ Programming Language.
Stroustrup's format of constexpr double real() const { return re; } is what my example ended up using, however without constexpr since my class didn't like it (I'm trying to understand why but still haven't got it yet).
A comment on the accepted answer of my question by user deidei says that std::valarray is "dynamic", which I guess here means that you can resize it. That might bring issues when it comes to memory, and I think that my values might have been overwritten somehow due to this fact.
#include <iostream>
#include <valarray>
#include <vector>
class A
{
public:
A(std::valarray<int> b, std::vector<int> c)
{
std::cout<< b[0] << std::endl;
};
std::valarray<int> get_b() const {return b;};
std::vector<int> get_c() const {return c;};
private:
std::valarray<int> b;
std::vector<int> c;
};
int main()
{
std::valarray<int> b = {1, 3};
std::vector<int> c = {4, 2, 8, 17};
A a(b,c);
std::cout<< a.get_b()[0] << std::endl; // returns a random large number such as 26618992
return 0;
}
What issue might be causing this problem?
[^1]: (inspired by the answer to my previous question, for those of you playing along at home)
My understanding was that since the constructor takes b and c as
arguments then they will be assigned to member variables of the same
name
This is incorrect. You can initialize member variable via member initializer list, via default initialization or by assigning values directly in the body of constructor. For example:
A(std::valarray<int> b, std::vector<int> c)
: b(b), c(c)
{...
or
private:
std::valarray<int> b = {1, 3};
std::vector<int> c = {4, 2, 8, 17};
or
A(std::valarray<int> b, std::vector<int> c)
{
this->b = b;
this->c = c;
...
You have done none of the above, so your valaray of int's is size of 0. When you return its copy and trying to access non-existing element
// returns a random large number such as 26618992
you get some garbage value from the memory.

How do I define a "unary predicate" for copy_if, etc in C++?

I'm trying to use std::copy_if() and I figured out somewhat how the syntax works from http://www.cplusplus.com/reference/algorithm/copy_if/ :
auto it = std::copy_if (foo.begin(), foo.end(), bar.begin(), [](int i){return !(i<0);} );
The last argument is the one that I am confused about. What are the brackets for? Can I use a function I wrote somewhere else as an argument and how would that work? Can I pass another argument to the function if I specify which variable to pass to it?
I guess my overall question is where I could find the syntax for these things. Using this example, I can declare some really simple things, but I'd like to be able to do more with it. I've found a few places that explain what a unary predicate should do and not do, but not actually how to declare one and what that would mean. I'm still somewhat new to the algorithms in c++ and hope to learn how to use them more effectively.
You can pass anything that behaves like a function as the predicate to copy_if. There are a few common things you can use:
1) Functions
Functions indeed act like functions, so they can be passed as a predicate to copy_if:
bool is_less_than_zero(int i) { return i < 0; }
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b), is_less_than_zero);
// now b will contain the elements {-2, -1}
}
Live Demo
2) Objects with an overloaded operator()
Objects can overload operator() so that they act like functions. These are often called "function objects" or "functors". This lets you store state, which can't be achieved with raw functions:
struct IsLessThan {
IsLessThan(int i) : i_{i} {}
bool operator()(int i) { return i < i_; }
int i_;
};
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b), IsLessThan(0));
// now b will contain the elements {-2, -1}
}
Live Demo
3) Lambdas
Lambdas are conceptually anonymous functions. In reality, they're just syntactic sugar for objects with an overloaded operator(), but that makes them a useful tool for creating simple predicates with little code:
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b),
[](int i){ return i < 0; });
// now b will contain the elements {-2, -1}
}
Live Demo
Since lambdas are really objects with an overloaded operator() they can also contain state, which is given via the lambda's capture list:
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
int number_to_compare_to = 0;
std::copy_if(a.begin(), a.end(), std::back_inserter(b),
[number_to_compare_to](int i){ return i < number_to_compare_to; });
// now b will contain the elements {-2, -1}
}
Live Demo
There are some facilities in the standard library to easily create function objects that contain state and use it to supply some of the parameters to a function (namely std::bind), but most of the places they were useful it's now easier to use a lambda instead. That is, the following code creates two objects that both act exactly the same:
bool first_less_than_second(int i, int j) { return i < j; }
int main() {
auto bind_less_than_zero = std::bind(first_less_than_second, std::placeholders::_1, 0);
auto lambda_less_than_zero = [](int i){ return first_less_than_second(i, 0); };
}
In general you should prefer the lambda version, but you will still sometimes see std::bind (or its pre-c++11 boost counterpart boost::bind) employed.

Assigning vector sizes as array lengths

So I am currently working on a program in c++, and I want to make the following decleration:
methodOne()
{
vector<int> one;
vector<int> two;
... assigning to one and two...
int a = one.size();
int b = two.size();
methodTwo(a, b);
}
methodTwo(int a, int b)
{
int array[a][b];
}
When I attempt this, I get an error: a and b must be constant
I have tried to assign a and b to const int a, const int b. However, that was no help. I was wondering if anyone knows how I can fix this kind of error. Thanks in advance for any help you are able to give!
An array's size must be known before the program runs. Its size is part its complete type, just like the element type itself.
You need something with a dynamic size instead. Use a std::vector<int> of size a * b:
methodTwo(int a, int b)
{
std::vector<int> array(a * b);
}
You could also use a std::vector<std::vector<int>> instead, but why take all the trouble? After all, you can access the one-dimensional vector's elements as if it was two-dimensional data structure by calculating the offsets accordingly:
methodTwo(int a, int b)
{
std::vector<int> array(a * b);
// ...
int x = 5;
int y = 6;
auto const element = array[y * a + x];
}
I see you already using vector so you can replace your array with
typedef std::vector< std::vector<int> > matrix;
matrix name(a, std::vector<int>(b));