Reputation: 4021
Is there a way, using C++11, to concatenate two std::vectors in one code line, with the first defined in a local variable, the second returned from a function:
#include <vector>
#include <iostream>
#include <iterator>
std::vector<int> getNewVector()
{
return {4,5,6};
}
int main(int argc, char** argv)
{
std::vector<int> dest;
std::vector<int> src{1,2,3};
dest = src + getNewVector(); //Error: no operator "+" matches these operands
return 0;
}
EDIT: differently from this question, that is not using C++11, I would like to know if the new C++11 standard give some useful functionality that would help my task. As an example, I've used the + operator even if it's not working, but just to give an idea of what I'm looking for.
Upvotes: 2
Views: 6097
Reputation: 1435
as per Maxim Egorushkin suggesion
a.insert(a.end(), b.begin(), b.end());
will be more efficient.
use std::transform,below code if you want to modify values of 'b' and insert into into 'a'
std::transform( b.begin(), b.end(), std::back_inserter(a), [](int i)->int { return i + delta; } );
complete code
int main()
{
std::vector<int> a = {1,2,3,4,5};
std::vector<int> b = {11,22,33,44,55};
//to copy
a.insert(a.end(), b.begin(), b.end());
//to transform
std::transform( b.begin(), b.end(), std::back_inserter(a), [](int i)->int { return i + delta; } );
return 0;
}
Upvotes: -1
Reputation: 136208
You can do that pretty easily using boost::range
library.
Ranges are going to be a part of C++ standard library. See Ranges for the Standard Library for more details.
Bonus point: only one memory allocation for the resulting vector.
#include <vector>
#include <boost/range/join.hpp>
int main() {
std::vector<int> a{1,2,3};
std::vector<int> b{4,5,6};
auto c = boost::copy_range<std::vector<int>>(boost::join(a, b));
}
Or, generalize it to more than two input sequences and types:
template<class T, class U>
auto join(T const& a, U const& b) -> decltype(boost::join(a, b)) {
return boost::join(a, b);
}
template<class T, class U, class... Args>
auto join(T const& a, U const& b, Args const&... args) -> decltype(boost::join(a, join(b, args...))) {
return boost::join(a, join(b, args...));
}
int main() {
std::vector<int> a{1,2,3};
std::list<int> b{4,5,6};
std::set<int> c{7,8,9};
auto d = boost::copy_range<std::vector<int>>(join(a, b, c));
}
Again, it does only one memory allocation in boost::copy_range<std::vector<int>>
because the input sequences lengths are known.
Upvotes: 2
Reputation: 1993
overloaded operator + takes 2x vectors, solution without library boost
#include <vector>
#include <iostream>
template<typename T>
std::vector<T> operator+(std::vector<T> vec1, const std::vector<T>&& vec2)
{
vec1.insert(vec1.end(), vec2.begin(), vec2.end());
return vec1;
}
std::vector<int> getNewVector()
{
return{ 4,5,6 };
}
template<typename T>
void displayVectors(const std::vector<T>& src, const std::vector<T>& dest, const std::vector<T>&& getNewVector)
{
std::cout << "src { ";
for (const auto& itr : src)
std::cout << itr << " ";
std::cout << "}" << std::endl;
std::cout << "getNewVector() { ";
for (const auto& itr : getNewVector)
std::cout << itr << " ";
std::cout << "}" << std::endl;
std::cout << "dest { ";
for (const auto& itr : dest)
std::cout << itr << " ";
std::cout << "}" << std::endl;
}
int main(int argc, char** argv)
{
std::vector<int> dest;
std::vector<int> src{ 1,2,3 };
displayVectors(src, dest, getNewVector());
dest = src + getNewVector();
std::cout << "After operation" << std::endl;
displayVectors(src, dest, getNewVector());
return 0;
}
or with move sematics
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
template<typename T>
std::vector<T> operator+(std::vector<T> vec1, const std::vector<T>&& vec2)
{
std::move(vec2.begin(), vec2.end(), std::back_inserter(vec1));
return vec1;
}
std::vector<int> getNewVector()
{
return{ 4,5,6 };
}
template<typename T>
void displayVectors(const std::vector<T>& src, const std::vector<T>& dest)
{
std::cout << "src { ";
for (const auto& itr : src)
std::cout << itr << " ";
std::cout << "}" << std::endl;
std::cout << "dest { ";
for (const auto& itr : dest)
std::cout << itr << " ";
std::cout << "}" << std::endl;
}
int main(int argc, char** argv)
{
std::vector<int> dest;
std::vector<int> src{ 1,2,3 };
displayVectors(src, dest);
dest = src + getNewVector();
std::cout << "After operation" << std::endl;
displayVectors(src, dest);
return 0;
}
Upvotes: 1
Reputation: 275300
namespace named_operator {
template<class D>struct make_operator{make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '+', Op> operator+( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator+( half_apply<Lhs, '+', Op>&& lhs, Rhs&& rhs )
-> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
boilerplate library first, then:
namespace ops {
struct concat_t:named_operator::make_operator<concat_t>{};
static const concat_t concat{};
template<class T, class A, class A2>
std::vector<T,A> named_invoke( std::vector<T,A> lhs, concat_t, std::vector<T,A2> const& rhs){
lhs.insert(lhs.end(), rhs.begin(), rhs.end());
return std::move(lhs);
}
}
using ops::concat;
writes the +concat+
operator. End use looks like:
int main(){
std::vector<int> a{1,2,3};
std::vector<int> b{7,8,9};
for( auto x: a +concat+ a +concat+ b )
std::cout <<x<<'\n';
}
Overloading naked +
is illegal in std
and fragile/dangerous in root namespace. Fragile due to "in a subnamespace doea not work", dangerous if you make it too greedy. concat_t
tag type avoids both.
And who wants to call a function. Prefix notation with ()
s annoying to chain.
The above copies the left hand side (unless lhs is a temporary), then concatinates the rhs. Adding move-contents to rhs is juat another named invoke function in namespace ops
. So a+a+b
copies a
, then extends the copy twice.
An expression template version could avoid hacing to resize more than once, for the usual issues.
Upvotes: 0
Reputation: 11002
We could exploit the fact that an l-value and r-value are being passed to the operator+
:
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
std::vector<int> getNewVector()
{
return {4, 5, 6};
}
template <class T>
T operator+(const T& l, T&& r)
{
T c{};
c.reserve(l.size() + r.size());
auto bi = std::back_inserter(c);
std::copy(l.begin(), l.end(), bi);
std::move(r.begin(), r.end(), bi);
return c;
}
int main()
{
std::vector<int> dest;
std::vector<int> src{1, 2, 3};
dest = src + getNewVector(); //uses operator "+"
return 0;
}
Upvotes: 1