I have an integer array as shown:
int ia[] = {1, 2, 3, 4, 5, 6};
I want to convert it to a list<int> and a vector<int>. The obvious way that comes to my mind is iterating over the array, and add the elements to the list<int> and vector<int>:
for (auto val: ia) {
ilist.push_back(val);
ivec.push_vack(val);
}
I just wanted to know, whether there is any other way, probably any available library function?
You can use a two-iterator constructor:
std::list<int> ilist(std::begin(ia), std::end(ia));
std::vector<int> ivec(std::begin(ia), std::end(ia));
If you don't have C++11 support for std::begin and std::end, you can use
std::list<int> ilist(ia, ia + 6);
where in real code you would aim to provide an array length function instead of using 6 explicitly.
Better still, you could role out your own begin and end function templates, for example
template< class T, std::size_t N >
T* my_end( const T (&a)[N] )
{
return &a[N];
}
Edit here's an array length function template:
template< class T, size_t N >
std::size_t size( const T (&)[N] )
{
return N;
}
Related
Is there a way using polymorphism to have a generic for set and multiset? as follows.
Note: but only for sets, (set, multiset)
template<typename T>
void foo(parent_set<T> &s) {
// do something
}
// main
set<int> s1 = {1, 2, 3, 4, 5};
foo(s1);
multiset<int> s2 = {1, 2, 2, 2, 2, 3};
foo(s2);
Well, why don't you make the whole container your template parameter?
template <class SetType>
void foo( SetType& s)
{
using T = typename SetType :: value_type;
enter code here
....
}
The restriction for the parameter to only be a set or multiset, as is usually done with templates, is enforced by the usage of the template parameter as a set. E.g. you call insert with a single parameter, and therefore you cannot pass a vector. If there is a third, unknown, container that has all the required interface, maybe it makes sense to allow it as well?
Consider a large memory container. In this simple example an std::vector<int>:
std::vector v = { 0, 1, 2, 3, 4, 5 };
std::span allows me create a lightweight view over the memory. Now I want to simply print the span:
template<typename T>
void print(std::span<T> span) {
std::cout << '[';
if (span.size())
std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));
std::cout << span.back() << "]\n";
}
int main() {
std::vector v = { 0, 1, 2, 3, 4, 5 };
print(std::span{ v });
}
output:
[0, 1, 2, 3, 4, 5]
now I want to make subsets (which is where the std::span actually becomes useful as a view). I can use iterators to specify my range and call this constructor(3) from std::span
template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );
But that doesn't work:
print(std::span{ v.begin() + 2, v.end() }); //error E0289
C++ no instance of constructor matches the argument list argument types are: (std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>, std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>)
there is the possibility of using the constructor(2) which takes a pointer and size:
print(std::span{ v.data() + 1, 3 }); //-> prints [1, 2, 3]
But that defeats the purpose of iterators.
How can I construct an std::span using iterators? Am I missing something?
full code:
#include <iostream>
#include <vector>
#include <span>
#include <algorithm>
template<typename T>
void print(std::span<T> span) {
std::cout << '[';
if (span.size())
std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));
std::cout << span.back() << "]\n";
}
int main() {
std::vector v = { 0, 1, 2, 3, 4, 5 };
print(std::span{ v.begin() + 2, v.end() });
}
until MSVC has implemented the constructor I will be using this make_span function:
template<typename It>
constexpr auto make_span(It begin, It end) {
return std::span<std::remove_pointer_t<It::pointer>>(&(*begin), std::distance(begin, end));
}
Using Visual Studio Community 2019 Version 16.7.5. Configuration: x64, Release. C++ Language Standard = /std:c++latest
You can construct a span using iterators, it has such a constructor (as added by P1394, which you can see in [views.span]):
template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );
It's just that MSVC's standard library doesn't implement it. The program compiles fine on gcc, as expected.
I have a vector of ints that I want to add multiple values too but too many values to add using a lot of push_backs. Is there any method of adding multiple values at the end of a vector. Something along the lines of this:
std::vector<int> values
values += {3, 9, 2, 5, 8, etc};
I found that boost has something like this, but I would like not having to include boost.
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
{
std::vector<int> myElements;
myElements += 1,2,3,4,5;
}
Which seems to be declared like this:
template <class V, class A, class V2>
inline list_inserter<assign_detail::call_push_back<std::vector<V,A> >, V>
operator+=( std::vector<V, A>& c, V2 v )
{
return push_back( c )( v );
}
Is there any C++/C++11 way to do this or, if not, how would it be implemented?
This should work:
std::vector<int> values;
values.insert( values.end(), { 1, 2, 3, 4 } );
Perhaps with insert:
values.insert( values.end(), {3, 9, 2, 5, 8, etc} );
Demo.
In order to present as much as possible solutions, this should work too:
for(const auto x : {11, 12, 13, 14})
v.push_back(x);
Demo.
You can just make an operator:
template <class T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::initializer_list<T> l)
{
lhs.insert(std::end(lhs), l);
return lhs;
}
You can mimic the boost boost::assign behavior
template <typename T>
class vector_adder
{
public:
std::vector<T>& v;
vector_adder(std::vector<T>& v):v(v)
{ }
vector_adder& operator,(const T& val)
{
v.push_back(val);
return *this;
}
};
template <typename T>
vector_adder<T> operator+=(std::vector<T>& v,const T& x)
{
return vector_adder<T>(v),x;
}
Then,
std::vector<int> v {1,2,3,4};
v += 11,12,13,14 ;
See here
You can do it by using the insert member function, as such:
vector<int> v;
int myarr[] {1, 2, 4, 5, 5, 6, 6, 8}; //brace initialization with c++11
v.insert(v.end(), myarr, myarr+8);
There was a previous answer that omitted the middle argument in the insert parameters, but that one does not work. There are several formats to follow for the insert method, which can be found here and the code snippet I wrote practically follows this format:
vectorName.insert(postion to start entering values, first value to enter, how many values to enter)
Note: That the last two arguments (i.e. myarr, myarr+8) use pointer arithmetics. myarr is the address in memory of the first element in the array, and the second value is the address of the 8th element. You can read about pointer arithmetic here.
Hope that helps!
Let's assume that I have a function that prints a set of numbers: 1, 2, 3, 4, 5 and these numbers can either be stored as an array, or, as a vector. In my current system I therefore have two functions that accept either of these parameters.
void printNumbers(std::vector<double> &printNumbers)
{
//code
//....
}
And therefore one that accepts an array..
void printNumbers(int* numbers)
{
//code
//...
}
This seems a waste of code, and, I was thinking that I could better take advantage of code re-use which got me thinking to this: Can I use a template to determine which type of input is being passed to the function? For example, whether it's a vector or an array or just a single integer value?
Here is the prototype below:
#include <iostream>
using namespace std;
template<class T>
void printNumbers(T numbers)
{
// code
// code
}
int main(int argc, char *argv[]) {
int numbers[] = {1, 2, 3, 4, 5};
printNumbers<array> (numbers);
}
Any help would be greatly appreciated.
The usual idiom is to pass iterators, one for the first element of the range, and one corresponding to "one past the end":
template<class Iterator>
void printNumbers(Iterator begin, Iterator end)
{
for (Iterator i = begin; i != end; ++i)
std::cout << *i << " ";
std::cout << "\n";
}
int main()
{
int numbers[] = {1, 2, 3, 4, 5};
printNumbers(numbers, numbers + 5);
printNumbers(std::begin(numbers), std::end(numbers); // C++11 version
std::vector<int> v{1,2,3,4,5};
printNumbers(v.begin(), v.end());
}
You could follow the example of the STL algorithms and accept an iterator range. Containers have their iterator types, and pointers can be used to iterate over arrays:
template <typename InputIterator>
void printNumbers(InputIterator start, InputIterator end) {
// print "*start", and iterate up to "end"
}
For convenience, you can overload this to accept containers and arrays directly:
template <typename Container>
void printNumbers(Container const & c) {
printNumbers(c.begin(), c.end());
}
template <typename T, size_t N>
void printNumbers(T (const & a)[N]) {
printNumbers(a, a+N);
}
In C++11 (or with your own begin and end functions) you can combine these:
template <typename Container>
void printNumbers(Container const & c) {
printNumbers(std::begin(c), std::end(c));
}
I have a n-dimensional Boost.MultiArray I initialize as follows:
const int n=3, size=4; //# of dimensions and size of one dimension
boost::multi_array<char,n> arr;
boost::array<size_t,n> extents; //size of each dimension
extents.assign(size); //assign size to each dimension -> {{4, 4, 4}}
arr.resize(extents);
So I have 4 lines of code to get the MultiArray, but I'd like to do it in one line.
Is there any simple way to generate an MultiArray with n dimensions each having size length (so I can write arr(samevaluearray(n,size))) or did I miss a handy constructor for MultiArray?
Edit: It should work without depending on a certain value of n, i.e. arr({{size,size}} would only work for n=2.
Since it may not be clear: boost::multi_array<char,n>(boost::extents[4][4][4]) correctly initializes a 4x4x4-array, but every time n is changed in the sourcecode, every initialization has to be updated by hand, so it's not an option.
You can encapsulate the creation of the array into an helper function:
template <typename T, size_t N>
boost::multi_array<T, N> make_regular_matrix(const size_t m)
{
boost::multi_array<T, N> arr;
boost::array<size_t, N> extents;
extents.assign(m);
arr.resize(extents);
return arr;
}
const int n = 3;
int size = 4; // Can be const as well, but this is not mandatory
auto arr = make_regular_matrix<char, n>(size);
If you can't use auto, you'll have to duplicate the template parameters:
boost::multi_array<char, n> arr = make_regular_matrix<char, n>(size);
The make_regular_matrix function could be shortened to use std::vector, as you did in your answer; I don't know if this implementation would be better. The aim of the helper function is to hide the creation of the array, but other versions could be written, for example to initialize the array elements with a given value:
template <size_t N, typename T> //switched order for deduction
boost::multi_array<T, N> make_regular_matrix(const size_t m, const T & value)
{
boost::multi_array<T, N> arr(std::vector<size_t>(n, m));
std::fill(arr.data(), arr.data() + arr.num_elements(), value);
return arr;
}
auto arr = make_regular_matrix<4>(3, 'z'); //creates a 3x3x3x3 matrix
//filled with 'z's
Turns out, std::vector has a constructor, that constructs a vector with a constant value repeated n times, so a possible solution looks like this:
const int n=2, size=4; //# of dimensions and size of one dimension
boost::multi_array<char,n> arr(std::vector<size_t>(n,size));
This initializes a n-dimensional multi_array with each dimension's size set to size.
From the Boost Multi-Array documentation, yes, you can initialize it one line:
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
The typedefs are for readability, one can just as easily do for your example:
boost::multi_array<int, 2> arr(boost::extents[2][4]);