Template function to read n-dimensional vector [duplicate] - c++

This question already has answers here:
Iterate throught n-dimensional vector c++
(2 answers)
how to print an n-dimensional array in c++
(2 answers)
Closed 28 days ago.
I am learning template programming. While doing so, I am trying to implement a template function to read n-dimensional vector.
My thought process is to recursively read through all dimensions and once I reach the innermost vector, start reading its elements.
Below is the (incorrect)code that I have tried.
template<typename Container>
void read_vectors(Container c){
read_vectors<decltype(begin(c))>(begin(c));
}
template<>
void read_vectors(vector<int> container){
for(auto i:container)
cout<<i<<endl;
}
int main(){
vector<vector<vector<int>>> intvectors{{{1,2,3},{1,2,3}},{{1,2,3}, {1,2,3}}};
read_vectors(intvectors);
return 0;
}
Any pointers on how that can be achieved is helpful.

Firstly, passing function parameters by value creates a copy of the function parameter:
template<>
void read_vectors(vector<int> container){
When this is reached, a complete copy of the passed-in vector is made just for the purpose of passing in this parameter. This accomplishes absolutely nothing at all, whatsoever, except to waste memory and precious electrons. In this case, the parameters should be passed by reference.
Secondly, for all other dimensions it's also necessary to iterate over all the other dimensions too. Nothing is going to iterate over them, automatically. So the final solution is:
#include <vector>
#include <iostream>
using namespace std;
template<typename Container>
void read_vectors(const Container &c)
{
for (const auto &i:c)
{
read_vectors(i);
}
}
template<>
void read_vectors(const vector<int> &container){
for(auto i:container)
cout<<i<<endl;
}
int main(){
vector<vector<vector<int>>> intvectors{{{1,2,3},{1,2,3}},{{1,2,3}, {1,2,3}}};
read_vectors(intvectors);
return 0;
}

Related

What is the structure of a std::vector?

I have made a recursive way of printing all of the elements of a vector, but it returns nonsense! and it throws a really strange exception:
Exception thrown: read access violation.
std::vector<int,std::allocator<int> >::operator[](...) returned nullptr.
And it outputs: 12358000
This is the code. What is the mistake I have made?
#include <iostream>
#include <vector>
using namespace std;
int printVec(vector<int>* foo) {
if ((*foo).empty())
return 0;
else {
cout << (*foo)[0];
printVec(foo + 4);
}
}
int main() {
vector<int> ref{ 1,2,3,4,5,6,7,8,9,0 };
printVec(&ref);
}
foo is a pointer to a std::vector<int>.
foo + 4 is adding 4 lots of sizeof(std::vector<int>) to foo in pointer arithmetic. There is not a std::vector at that location, so the behaviour of printVec(foo + 4) is undefined.
The expression (*foo)[0] is calling the overloaded [] operator on a std::vector which access the first element in the vector. If there is no element at that position then the behaviour of the program is undefined.
What is the mistake I have made?
You are using a pointer to a single vector and treat it as if it points into an array of std::vector<int>. It is only allowed to increment pointers that point to elements in arrays (actually you are allowed to get a pointer one past an object, but not more). A single std::vector is not an array and your code invokes undefined behavior by incrementing foo here: printVec(foo + 4);.
If you want to "point to" elements of the vector use iterators:
#include <iostream>
#include <vector>
using namespace std;
template <typename IT>
void printVec(IT current, IT end) {
if (current == end) return;
else {
cout << *current;
printVec(current+1,end);
}
}
int main() {
vector<int> ref{ 1,2,3,4,5,6,7,8,9,0 };
printVec(ref.begin(),ref.end());
}
What is the structure of a std::vector?
You need not know nor care. If you want to iterate elements use iterators. If you want to access the underlying array use .data().

C++: Sort a vector<struct> (where struct has 2 integers) based on the one of the integers of struct [duplicate]

This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 3 years ago.
In the below C++ snippet,
HOW TO SORT the vector "TwoIntsVec" BASED ON the element "int a" in TwoInts struct. i.e. i need to place the "TwoIntsVec[i] which has the least "TwoIntsVec[i].a" in the 1st place and so on in increasing order of "TwoIntsVec[i].a".
In the below example the vector elemnt struct having 7,3 should be placed 1st as 7 is the least "a" and so on.
struct TwoInts
{
int a;
int b;
};
void PushToVector(int a, int b, std::vector<TwoInts>& TwoIntsVec)
{
TwoInts temp;
temp.a = a;
temp.b = b;
TwoIntsVec.push_back(temp);
}
int main()
{
std::vector<TwoInts> TwoIntsVec;
PushToVector(21,3,TwoIntsVec);
PushToVector(7,3,TwoIntsVec);
PushToVector(12,3,TwoIntsVec);
PushToVector(9,3,TwoIntsVec);
PushToVector(16,3,TwoIntsVec);
// Below sort would NOT work here, as TwoIntsVec is
// not a std::vector<int>
std::sort( TwoIntsVec.begin(), TwoIntsVec.end());
// HOW TO MAKE THE SORT BASED ON the element "int a" in
TwoInts struct
}
You need to pass an appropriate comparison function to std::sort, as there is no appropriate comparison operator available for TwoInts. See overload #3 here with the description of this comparison parameter:
comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if the first argument is less than (i.e. is ordered before) the second. [...]
One C++11 option is to pass a lambda:
std::sort( TwoIntsVec.begin(), TwoIntsVec.end(),
[](const TwoInts& lhs, const TwoInts& rhs){ return lhs.a < rhs.a; });
If you find that this requires too much typing, you can construct a predicate with Boost HOF like this:
#include <boost/hof/proj.hpp>
#include <boost/hof/placeholders.hpp>
using namespace boost::hof;
std::sort(TwoIntsVec.begin(), TwoIntsVec.end(), proj(&TwoInts::a, _ < _));
Or, as a C++20 teaser:
std::ranges::sort(TwoIntsVec, std::less<>{}, &TwoInts::a);
As a side note, I'd recommend you to fill the vector directly via
// Less complicated than doing the same thing in a function:
TwoIntsVec.push_back({21, 3});
TwoIntsVec.push_back({7, 3});
// ...

erase() does not work on a STL vector inside a structure/object? [duplicate]

This question already has answers here:
How do I erase an element from std::vector<> by index?
(16 answers)
Closed 4 years ago.
I have an object that contains an STL vector. I start with the vector being size zero and use push_back to add to it. So, push_back works fine.
In my code, each element in the vector represents an atom. Thus the object this STL vector is inside is a "molecule".
When I try to remove an atom from my molecule i.e., erase one of the elements from the array, the erase() function does not work. Other methods do work such as size() and clear(). clear() removes all elements though, which is overkill. erase() is exactly what I want, but it doesn't work for some reason.
Here is an incredibly simplified version of my code. It does, however, represent the problem exactly.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class atomInfo
{
/* real code has more variables and methods */
public:
atomInfo () {} ;
};
class molInfo
{
/* There is more than 1 atom per molecule */
/* real code has more variables and methods */
public:
vector <atomInfo> atom;
molInfo () {};
};
int main ()
{
int i;
molInfo mol;
for( i=0; i<3 ; i++)
mol.atom.push_back( atomInfo() );
//mol.atom.clear() ; //Works fine
mol.atom.erase(1) ; //does not work
}
I get the following error when I use erase():
main.cpp: In function ‘int main()’: main.cpp:39:21: error: no matching
function for call to ‘std::vector::erase(int)’
mol.atom.erase(1) ;
It looks like you thought std::vector::erase took an index from the start of the container.
It's not clear where you got this idea from, as it is not what the documentation says.
These functions work with iterators.
Fortunately, with vectors, you can get the effect you want by adding a number to an iterator.
Like this:
mol.atom.erase(mol.atom.begin() + 1);
Said documentation in fact does have an example to this effect.

Chaining non overlaping, non-contiguous iterators in c++ (/boost) [duplicate]

This question already has answers here:
Skip an entry of a random iterator
(2 answers)
Closed 8 years ago.
(Caveat: I'm a beginner in C++).
Consider this simple example:
#include <iostream>
#include <random>
#include <algorithm>
using namespace std;
template<class RandomAccessIterator1>
typename std::iterator_traits<RandomAccessIterator1>::value_type
foo(RandomAccessIterator1 firsta,RandomAccessIterator1 lasta,float store[]){
const float x1=*firsta;
int i=0;
for (RandomAccessIterator1 it=firsta;it!=lasta+1;it++){
store[i++]=x1-*it;
}
return(*(firsta+3));
}
int main(){
const int n=*nr;
int i;
float x[n],store[n];
for(i=0;i<n;i++) x[i]=(float)rand()/(float)RAND_MAX;
std::sort(x,x+n);
float a2=(x[1]+x[n-1])*0.5f;
int m0=std::upper_bound(x,x+n,a2)-x;
int m1=m0/2-1;
float var=foo(x,x+m0,store);
for(i=0;i<m0-1;i++) std::cout<< store[i] << std::endl;
}
My problem is that I need foo to not take x[m1] into account. Simply 'forget' that element as it were. But I don't really have access to the real foo itself: everything has to be done on the level of the inputs to foo, not the function itself. In other word, I need to somehow make firsta,lasta the bounds of
an RandomAccessIterator that contains all the elements in the range [firsta,lasta) except the m1-th. I don't have anything against using boost or other external
open source libraries. My only problem is that whatever solution should be O(1).
Oh, and I don't even know if it is possible.
I put the tag boost because there seems to be a series of related question on SO that solve this problem using boost.
If you can't do anything in foo that only really leaves you with the option of copying everything but the m1-th value into a vector (or some other random access container).
You could create a new iterator class that knows about values to skip. Something that looks roughly like this:
class MyIterator
{
public:
MyIterator(containerClass & myContainer, value_type valueToSkip);
private:
containerClass::iterator baseIterator;
value_type skipValue;
};
Obviously I've left out a lot of the details.

How do I check if a value is contained in a vector? C++ [duplicate]

This question already has answers here:
How to find out if an item is present in a std::vector?
(18 answers)
Closed 12 months ago.
I have a vector that I am trying to perform a contains function on. I am receiving some sort of casting error and I can't piece together a solution. I am also wanting to know whether or not what I am doing is the appropriate way to check if a vector contains a value.
Here is the code:
#include "stdafx.h"
#include <vector>
static void someFunc(double** Y, int length);
static bool contains(double value, std::vector<double> vec);
int main()
{
double doubleArray[] = { 1, 2, 3, 4, 5 };
double *pDoubleArray = doubleArray;
int size = sizeof doubleArray / sizeof doubleArray[0];
someFunc(&pDoubleArray, size);
return 0;
}
static void someFunc(double** Y, int length)
{
std::vector<double> vec();
for(int i = 0; i < 10; i++)
{
//error: 'contains' : cannot convert parameter 2 from 'std::vector<_Ty> (__cdecl *)(void)' to 'std::vector<_Ty>'
if(contains(*(Y[i]), vec))
{
//do something
}
}
}
static bool contains(double value, std::vector<double> vec)
{
for(int i = 0; i < vec.size(); i++)
{
if(vec[i] == value)
{
return true;
}
}
return false;
}
When you declare a variable with it's default constructor, you don't put () after it (although it's optional when you use new to allocate space on the free store). So this line:
std::vector<double> vec();
should become
std::vector<double> vec;
If you leave it as you did, it thinks that line is a function prototype of a function called vec taking no parameters and returning a std::vector<double>, which is why you're getting a compiler error.
And yes, your code for finding an item will work (it's called a linear search). Also if you want to, you can use std::find:
if (std::find(vec.begin(), vec.end(), value) != vec.end())
// found value in vec
If your vector is in sorted order, you can also use binary_search which is much faster than find, and the usage is the same except binary_search returns a bool instead of an iterator (so you don't need to test it against vec.end()). Make sure you include the algorithm header if you use either of these.
std::vector<double> vec();
Oddly, this does not declare a vector using the default constructor. This declares a function taking no arguments and returning a vector. Try this instead:
std::vector<double> vec;
You can use std::find to check an STL datastructure to contain a certain value.