Convert from std::vector<double> to std::vector<int>

A

Anonymous

Is there a non-brute force method of doing this?
transform() looked likely but had no predefined function object.


std::vector<double> src;
std::vector<int> dest;

std::vector<double>::size_type size = src.size();
dest.reserve(size);
for (std::vector<int>::size_type i = 0;
i < size;
i++)
{
dest = static_cast<int>(src);
}
 
A

Andrew Koenig

Is there a non-brute force method of doing this?
transform() looked likely but had no predefined function object.
std::vector<double> src;
std::vector<int> dest;

std::vector<double>::size_type size = src.size();
dest.reserve(size);
for (std::vector<int>::size_type i = 0;
i < size;
i++)
{
dest = static_cast<int>(src);
}


How about this?

std::vector<int> dest(src.begin(), src.end());

I can't recall any requirement that the iterators used to initialize a
vector must refer to values of the same type as the vector elements.
 
M

Malte Starostik

Andrew said:
Is there a non-brute force method of doing this?
transform() looked likely but had no predefined function object.

std::vector<double> src;
std::vector<int> dest;

std::vector<double>::size_type size = src.size();
dest.reserve(size);
for (std::vector<int>::size_type i = 0;
i < size;
i++)
{
dest = static_cast<int>(src);
}



How about this?

std::vector<int> dest(src.begin(), src.end());

I can't recall any requirement that the iterators used to initialize a
vector must refer to values of the same type as the vector elements.


Right, that's the straightforward way and it works, but can result in a
rather longish warning about the double->int conversion:

/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:
In
function `_OutputIter std::__copy(_RandomAccessIter, _RandomAccessIter,
_OutputIter, std::random_access_iterator_tag) [with _RandomAccessIter =
double*, _OutputIter = int*]':
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:266:
instantiated from `_OutputIter std::__copy_aux2(_InputIter,
_InputIter, _OutputIter, __true_type) [with _InputIter = double*,
_OutputIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:303:
instantiated from `_OutputIter std::__copy_ni2(_InputIter, _InputIter,
_OutputIter, __false_type) [with _InputIter = double*, _OutputIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:314:
instantiated from `_OutputIter std::__copy_ni1(_InputIter, _InputIter,
_OutputIter, __true_type) [with _InputIter =
__gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, _OutputIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:349:
instantiated from `_OutputIter std::copy(_InputIter, _InputIter,
_OutputIter) [with _InputIter = __gnu_cxx::__normal_iterator<double*,
std::vector<double, std::allocator<double> > >, _OutputIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_uninitialized.h:76:
instantiated from `_ForwardIter
std::__uninitialized_copy_aux(_InputIter, _InputIter, _ForwardIter,
__true_type) [with _InputIter = __gnu_cxx::__normal_iterator<double*,
std::vector<double, std::allocator<double> > >, _ForwardIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_uninitialized.h:112:
instantiated from `_ForwardIter std::uninitialized_copy(_InputIter,
_InputIter, _ForwardIter) [with _InputIter =
__gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, _ForwardIter = int*]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_vector.h:829:
instantiated from `void std::vector<_Tp,
_Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator,
std::forward_iterator_tag) [with _ForwardIterator =
__gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, _Tp = int, _Alloc = std::allocator<int>]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_vector.h:807:
instantiated from `void std::vector<_Tp,
_Alloc>::_M_initialize_dispatch(_InputIter, _InputIter, __false_type)
[with _InputIter = __gnu_cxx::__normal_iterator<double*,
std::vector<double, std::allocator<double> > >, _Tp = int, _Alloc =
std::allocator<int>]'
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_vector.h:289:
instantiated from `std::vector<_Tp, _Alloc>::vector(_InputIterator,
_InputIterator, typename std::_Vector_base<_Tp,
_Alloc>::allocator_type&) [with _InputIterator =
__gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, _Tp = int, _Alloc = std::allocator<int>]'
foo.cpp:6: instantiated from here
/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.4/include/g++-v3/bits/stl_algobase.h:241:
warning: converting
to `int' from `double'

Cheers,
Malte
 
D

Donovan Rebbechi

Is there a non-brute force method of doing this?
transform() looked likely but had no predefined function object.

I'd just wrap static_cast in a function object, e.g.

template <typename T>
struct Static_cast {
template <typename U>
T operator () (const U& x) const { return static_cast<T> (x); }
};

Not pretty, but gets the job done and shuts the compiler up. I happen to
believe that being able to explicitly "cast" one container to another is a
good enough reason to write a 5 line function object.

Cheers,
 
M

Malte Starostik

Donovan said:
I'd just wrap static_cast in a function object, e.g.

template <typename T>
struct Static_cast {
template <typename U>
T operator () (const U& x) const { return static_cast<T> (x); }
};

Not pretty, but gets the job done and shuts the compiler up. I happen to
believe that being able to explicitly "cast" one container to another is a
good enough reason to write a 5 line function object.

I totally agree. Minor nitpick though: no need to use static_cast to
convert int to double. The functional notation is enough and IMHO
conveys less of the feeling of doing something bad ;-)
return T( x );
Of course that limits a function object like the one above.

Cheers,
Malte
 
P

Pete Becker

Malte said:
Right, that's the straightforward way and it works, but can result in a
rather longish warning about the double->int conversion:

So turn of that G** D***** warning. Just because some compiler writer
thinks you can't be trusted to convert doubles to ints doesn't mean you
have to believe it.
 
P

Pete Becker

Donovan said:
Not pretty, but gets the job done and shuts the compiler up. I happen to
believe that being able to explicitly "cast" one container to another is a
good enough reason to write a 5 line function object.

Even better is to use the built-in conversions as they were designed to
be used. Writing a five line function object just to satisfy some
compiler writer's notion of good form is a waste of time.
 
D

Donovan Rebbechi

Even better is to use the built-in conversions as they were designed to
be used. Writing a five line function object just to satisfy some
compiler writer's notion of good form is a waste of time.

But chasing some error that the compiler warned you about is a potential
timesink, because you turned down warning levels, or because the warnings
were hidden among dozens of lines of noise is an even bigger waste of time.
Writing a small wrapper around static_cast is a minor inconvenience at worst.
Of course you understand this -- so how would you go about managing the
problem of noisy warnings ?

Suppose there is a "borderline" warning that is sometimes useful and sometimes
just annoying. (I'd consider this to be such an example) Do you turn warning
levels down, or do you turn them up, but then find some way to supress or
filter the resulting noise ? Or is it your opinion that my premise is just
plain wrong, and there is no such thing as a "borderling" warning ?

Cheers,
 
P

Pete Becker

Donovan said:
But chasing some error that the compiler warned you about is a potential
timesink, because you turned down warning levels, or because the warnings
were hidden among dozens of lines of noise is an even bigger waste of time.

And chasing some error that the compiler didn't warn you about because
someone added a cast to get rid of the warning is a potential timesink,
Writing a small wrapper around static_cast is a minor inconvenience at worst.\

Any time you're rewriting correct, meaningful code in order to silence a
warning you're wasting time. And, of course, you can't assume that
someone who added a cast had thought about what the code did; they might
have added it just to silence the warning. After all, that's the goal:
your code should compile without warnings. Doesn't matter if it's
correct said:
Of course you understand this -- so how would you go about managing the
problem of noisy warnings ?

Turn 'em off.
Suppose there is a "borderline" warning that is sometimes useful and sometimes
just annoying. (I'd consider this to be such an example) Do you turn warning
levels down, or do you turn them up, but then find some way to supress or
filter the resulting noise ? Or is it your opinion that my premise is just
plain wrong, and there is no such thing as a "borderling" warning ?

Too many programmers today treat the compiler as a surrogate brain, and
rely on warnings to remind them that they haven't thought about the
consequences of what they've done. If you're writing code that converts
a double to an int you'd better know what the limitations on that are,
and you'd better take the time to analyze where the double comes from
and assure yourself that the conversion will do what you need to do.
That's basic software engineering. Warnings don't change that. At best
they become a checklist of places where you haven't finished your work.
There are much more effective ways of doing that, beginning with not
leaving a piece of code until you understand it. That way you don't have
to remember to look at it again later.

Tom DeMarco, in a book called "Controlling Software Projects,"
recommended (perhaps tongue in cheek) that programmers not be allowed to
use compilers; compiling their code would be part of the test phase, not
the development phase.
 
Y

Yuriy Solodkyy

I was always wondering why compiler writers won't create a common
numeration or classification for at least common errors and warnings. In
this way developers would have been able to temporary disable and then
reenable a particular warning via #pragma (don't know how portable
pragmas are, but it's a nice way in some compilers to explicitly say to
compiler that you know what you are doing).

Yuriy
 
D

Duane Hebert

Pete Becker said:
So turn of that G** D***** warning. Just because some compiler writer
thinks you can't be trusted to convert doubles to ints doesn't mean you
have to believe it.

Or just use a static_cast.
 
P

Pete Becker

Duane said:
Or just use a static_cast.

To "just use a static_cast" in this case requires writing a function
object to pass to an algorithm, instead of simply using the vector
constructor that takes a pair of iterators.
 
H

Howard

Tom DeMarco, in a book called "Controlling Software Projects," recommended
(perhaps tongue in cheek) that programmers not be allowed to use
compilers; compiling their code would be part of the test phase, not the
development phase.

Ah, that takes me back to my early years in college: drawing flowcharts,
writing pseduo-code, filling out coding forms, entering the final code
verbatim from those forms, submitting it all to a batch system, and waiting
until the next day to find out I'd left out a period on the third line of my
COBOL app, resulting in seventeen pages of errors and an automatic reduction
of my best possible grade by 5%. I sure do miss those exciting, productive
times. Sigh...

:)

-Howard
 
H

Howard Hinnant

Pete Becker said:
To "just use a static_cast" in this case requires writing a function
object to pass to an algorithm, instead of simply using the vector
constructor that takes a pair of iterators.

Or instead maybe write a templated "casting iterator" which would
certainly be more trouble up front, but more reusable down the road.

Maybe something like (untested and many details left out):

template <class To, class From>
class op_static_cast
{
...
typedef typename iterator_traits<To>::value_type value_type;
value_type operator () (const From& f) const
{return static_cast<value_type>(*f);}
};

template <class Cast>
class cast_iterator
{
...
value_type operator*() const {return c_(i_);}
...
private:
from i_;
Cast c_;
};

vector<double> vd;
....
typedef cast_iterator
<
op_static_cast
<
vector said:
vector<int> vi(It(vd.begin(), It(vd.end()));

This is unfortunately likely to bend (or break) some rules on the
iterator categories (like forward iterators must return references).
But it is also likely to work flawlessly (assuming your compiler can
inline everything).

All that being said, I sympathize with Pete's argument. But sometimes
the warning level for a piece of code is a political issue instead of a
technical issue.

-Howard
 
P

Pete Becker

Howard said:
Or instead maybe write a templated "casting iterator" which would
certainly be more trouble up front, but more reusable down the road.

Sure, there are all sorts of things people can do to smuggle an
unnecessary cast into their code. But casts should never become routine
parts of coding. They indicate that there is something out of the
ordinary going on. The simplest, clearest, and most reusable solution to
the original problem (remember that?) is the one I started with: turn
off the warning.
 
K

Kurt Stutsman

Pete said:
Sure, there are all sorts of things people can do to smuggle an
unnecessary cast into their code. But casts should never become routine
parts of coding. They indicate that there is something out of the
ordinary going on. The simplest, clearest, and most reusable solution to
the original problem (remember that?) is the one I started with: turn
off the warning.

I fail to see how this is an unnecessary cast. What you are doing is casting,
whether implicitly or explicitly. And I'd much rather keep the warning on so
that if for some reason I mistakenly try to assign a double to an int in the
wrong place, I'm warned about it.
 
P

Pete Becker

Kurt said:
I fail to see how this is an unnecessary cast. What you are doing is
casting, whether implicitly or explicitly.

A cast is something you write in your source code; there is no such
thing as an implicit cast. What you're talking about is a conversion.
The compiler will do the conversion, with or without the cast. You don't
need it to make your code correct. You need it to make the compiler shut
up about code that's well defined and meaningful.
And I'd much rather keep the
warning on so that if for some reason I mistakenly try to assign a
double to an int in the wrong place, I'm warned about it.

And, as I'm getting tired of saying, this "safety" is illusory. If
you're not paying attention to what you're doing you're going to make
mistakes. Warnings may catch some carelessness, but not all. If you
don't trust yourself to write code that's correct, take a break and
start fresh later.

Writing five lines of code instead of one just to tell the compiler that
I know how to write valid C++ code doesn't strike me as a good use of my
time.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Yuriy said:
I was always wondering why compiler writers won't create a common
numeration or classification for at least common errors and warnings. In
this way developers would have been able to temporary disable and then
reenable a particular warning via #pragma (don't know how portable
pragmas are, but it's a nice way in some compilers to explicitly say to
compiler that you know what you are doing).

In that case, surely someone will write a compiler that check if the
programmer seems to really knows what is doing when using that pragma and
emits a warning if the check fails.
 
K

Kurt Stutsman

Pete said:
A cast is something you write in your source code; there is no such
thing as an implicit cast. What you're talking about is a conversion.
The compiler will do the conversion, with or without the cast. You don't
need it to make your code correct. You need it to make the compiler shut
up about code that's well defined and meaningful.
Fine, I misdescribed it as casting instead of implicit conversion. You are
still converting it from one type to another that cannot support the same
values (3.6 to an int will not give you 3.6 obviously). If I'm going to do
something that loses information, I personally prefer to have something
explicitly describing that (like a static_cast said:
And, as I'm getting tired of saying, this "safety" is illusory. If
you're not paying attention to what you're doing you're going to make
mistakes. Warnings may catch some carelessness, but not all. If you
don't trust yourself to write code that's correct, take a break and
start fresh later.

I don't think anyone writes completely perfect code all the time. We are,
after all, human. We also write very large code bases from time to time or use
other people's libraries in addition our own. It's possible we might make a
mistake during all this perfect code writing. A warning about it at compile
time sure is nicer than trying to find why something is not working because
I'm losing a 0.6 by mistake somewhere.
Writing five lines of code instead of one just to tell the compiler that
I know how to write valid C++ code doesn't strike me as a good use of my
time.

And using templates you write this 5 lines of code once. That's some pretty
precious time.
 
P

Pete Becker

Kurt said:
And using templates you write this 5 lines of code once. That's some
pretty precious time.

And you compile it every time you use it. Pretty soon you find that all
these wonderful templates are killing your turnaround times, and
sometimes your compiler.
 

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

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,834
Latest member
BuyCannaLabsCBD

Latest Threads

Top