On vectors equality and conversion

A

Andrea Crotti

I often need to check for equality between vectors and I thought that ==
was already defined, but apparently it's not, so I did this

--8<---------------cut here---------------start------------->8---
template <typename X, typename Y>
bool vectorEquals(const vector<X>& first, const vector<Y>& second) {
if (first.size() != second.size())
return false;

for (size_t i=0; i < first.size(); ++i)
if (first != second)
return false;

return true;
}
--8<---------------cut here---------------end--------------->8---

which is pretty standard way to do it I guess, and I should get a
compile time error if the == is not defined for what I want to check,
right?

And the other thing is that I want to be able to "convert" vector of
different types.
Actually I mainly care to do

vector<X> <-> vector<unsigned char>

So I tried this thing::

template <typename INP, typename OUT>
vector<OUT> vectorConversion(const vector<INP>& input) {
size_t size_inp = sizeof(INP);
size_t size_out = sizeof(OUT);
// make sure the sizeof are multiples between them, otherwise it doesn't work!
assert(((size_inp % size_out) == 0) || ((size_out % size_inp) == 0));
vector<OUT> res;
size_t size = (size_inp * input.size()) / size_out;
// I'm sure it's always 1
res.resize(size);
// first convert to network order and then copy brutally
memcpy(&res[0], &input[0], size);
return res;
}


and in one way it works but in the other it doesn't.
vector<int> x = {1,2,3}
// simplifying
convert(convert(x)) = {1, 0, 0}

Any idea?
 
L

Luc Danton

I often need to check for equality between vectors and I thought that ==
was already defined, but apparently it's not, so I did this

--8<---------------cut here---------------start------------->8---
template<typename X, typename Y>
bool vectorEquals(const vector<X>& first, const vector<Y>& second) {
if (first.size() != second.size())
return false;

for (size_t i=0; i< first.size(); ++i)
if (first != second)
return false;

return true;
}
--8<---------------cut here---------------end--------------->8---

which is pretty standard way to do it I guess, and I should get a
compile time error if the == is not defined for what I want to check,
right?

And the other thing is that I want to be able to "convert" vector of
different types.
Actually I mainly care to do

vector<X> <-> vector<unsigned char>

So I tried this thing::

template<typename INP, typename OUT>
vector<OUT> vectorConversion(const vector<INP>& input) {
size_t size_inp = sizeof(INP);
size_t size_out = sizeof(OUT);
// make sure the sizeof are multiples between them, otherwise it doesn't work!
assert(((size_inp % size_out) == 0) || ((size_out % size_inp) == 0));
vector<OUT> res;
size_t size = (size_inp * input.size()) / size_out;
// I'm sure it's always 1
res.resize(size);
// first convert to network order and then copy brutally
memcpy(&res[0],&input[0], size);
return res;
}


and in one way it works but in the other it doesn't.
vector<int> x = {1,2,3}
// simplifying
convert(convert(x)) = {1, 0, 0}


I'm a bit confused by that notation: is this supposed to be pseudo-code,
meaning that the result of a back-and-forth conversion of { 1, 2, 3 } is
{ 1, 0, 0 }? I'd suggest using == for equality in your pseudo-code, as
in code. I'd also suggest posting something compilable (or really close
to compilable) instead of recollecting because I suspect that the
template arguments are the other way around, such that you can call
collect<int> said:
Any idea?

The reason that you might not see all the methods you need or want on
standard classes is that the design of those classes is generic rather
than object-oriented. This means that a class like std::vector is
designed to manage the lifetime of its elements (with some guarantees
like contiguity) and provide access to them and no further.

To operate on elements of a standard container one usually uses an
algorithm rather than a method. In your case, a solution could be:

#include <algorithm>

int
main()
{
std::vector<int> v1 = /* initialize */
std::vector<int> v2 = /* initialize */

// you can use cbegin and cend instead with C++0x
bool res = std::equal(v1.begin(), v1.end(), v2.begin());

// use res here
}

Note that some algorithm might be found in the <numeric> header, too.

For your other problem I suspect that the third argument to memcpy
should be size_inp * input.size().
 
L

Luc Danton

[...]
int
main()
{
std::vector<int> v1 = /* initialize */
std::vector<int> v2 = /* initialize */

This example would maybe make more sense if the two vectors had
_different_ element types, since two vectors with the same element type
*can* be compared with operator== as pointed out by gwowen.
 
A

Andrea Crotti

Luc Danton said:
I'm a bit confused by that notation: is this supposed to be
pseudo-code, meaning that the result of a back-and-forth conversion of
{ 1, 2, 3 } is { 1, 0, 0 }? I'd suggest using == for equality in your
pseudo-code, as in code. I'd also suggest posting something compilable
(or really close to compilable) instead of recollecting because I
suspect that the template arguments are the other way around, such
that you can call collect<char>, collect<int>, collect<long> and so on
(whereas collect(a_vector) is a compile error). This would help us
help you.


The reason that you might not see all the methods you need or want on
standard classes is that the design of those classes is generic rather
than object-oriented. This means that a class like std::vector is
designed to manage the lifetime of its elements (with some guarantees
like contiguity) and provide access to them and no further.

To operate on elements of a standard container one usually uses an
algorithm rather than a method. In your case, a solution could be:

#include <algorithm>

int
main()
{
std::vector<int> v1 = /* initialize */
std::vector<int> v2 = /* initialize */

// you can use cbegin and cend instead with C++0x
bool res = std::equal(v1.begin(), v1.end(), v2.begin());

// use res here
}

Note that some algorithm might be found in the <numeric> header, too.

For your other problem I suspect that the third argument to memcpy
should be size_inp * input.size().

Ah great I forgot to look somewhere else.
Then I don't need that al all, == when is the same type and std::equals
otherwise.


About the conversion yes the bug was were you spotted it, thanks a lot
now it works...

But isn't there a better way to do it??
 
G

gwowen

   std::vector<int> v1 = /* initialize */
   std::vector<int> v2 = /* initialize */

   // you can use cbegin and cend instead with C++0x
   bool res = std::equal(v1.begin(), v1.end(), v2.begin());

This only works if v1.size() == v2.size(). If v1 has fewer elements
than v2, this will only check the number of elements in v1. If v2 has
fewer elements than v1, behaviour is undefined (I can understand *why*
this is the case, but I hate the design decision).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top