Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: What is the correct cast for offseting to std::vector iterator?

I have a function that takes a std::vector of doubles, and copies them to another vector, but at a particular offset (assume there is sufficient space):

void copy_stuff(const std::vector<double> & data,
                std::vector<double> & dest,
                size_t dest_offset) {
    std::copy(data.begin(), data.end(), dest.begin() + dest_offset);
}

This results in a C++11 clang compiler -Weverything warning centered on the + dest_offset part:

Implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to 'difference_type' (aka 'long').

I'm not sure how I should cast the expression dest.begin() + dest_offset in order to eliminate this warning. Casting the result to a double * does not compile:

    std::copy(data, data + data_size, static_cast<double *>(dest.begin() + dest_offset));

Cannot cast from type 'std::__1::__wrap_iter' to pointer type 'double *'.

I had considered using vector indexing and then taking the address:

    std::copy(data, data + data_size, &dest[dest_offset]);

This seems to eliminate the warning in this case, but doesn't compile if I try to use the same pattern with the source vector, i.e. with an offset involved with the first or second parameter of std::copy. For example:

static void copy_stuff_differently(const std::vector<double> & data,
                                   std::vector<double> & dest,
                                   size_t offset) {
    std::copy(data.begin() + offset, data.end(), dest.begin());
}

Gives the same original warning of implicit conversion on the + offset. Attempting to use the address-of-index might suggest:

    std::copy(&data[offset], data.end(), dest.begin());

Or a different but similar case:

    std::copy(data.begin(), &data[offset], dest.begin());

However both cause a similar error:

test.cpp:8:3: error: no matching function for call to 'copy'
  std::copy(&data[offset], data.end(), dest.begin());
  ^~~~~~~~~
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iterator:1286:48: note:
      candidate template ignored: deduced conflicting types for parameter '_Ip' ('const double *' vs.
      'std::__1::__wrap_iter<const double *>')
    template <class _Ip, class _Op> friend _Op copy(_Ip, _Ip, _Op);
                                               ^

I'm looking for a consistent and warning-free way to handle such offsets. What is the right way to handle offsets into a vector and avoid such errors and warnings?

like image 434
davidA Avatar asked Jun 11 '17 05:06

davidA


People also ask

What is the type of an iterator c++?

Input iterators are one of the five main types of iterators present in C++ Standard Library, others being Output iterators, Forward iterator, Bidirectional iterator and Random – access iterators.

Can I subtract iterators?

If two unrelated iterators (including pointers) are subtracted, the operation results in undefined behavior [ISO/IEC 14882-2014]. Do not subtract two iterators (including pointers) unless both point into the same container or one past the end of the same container.

What type does std :: distance return?

std::distance returns a signed value. I am assuming you are trying to get the distance in such a way that -2 AND 2 would be considered as 2 . The abs function gives you the absolute value which means that whatever the sign of the input, you always get a positive value back.

What is iterator in STL in c++?

An iterator is used to point to the memory address of the STL container classes. For better understanding, you can relate them with a pointer, to some extent. Iterators act as a bridge that connects algorithms to STL containers and allows the modifications of the data present inside the container.


1 Answers

I'm not sure how I should cast the expression dest.begin() + dest_offset in order to eliminate this warning.

The warning is just telling you that dest_offset is expected to be of the type std::vector::difference_type, but it's size_t.

You can do the conversion explicitly to eliminate the warning (note that if the source value can't be represented in difference_type the result is implementation-defined). e.g.

dest.begin() + static_cast<std::vector<double>::difference_type>(dest_offset)

Or declare the parameter dest_offset with the type difference_type from the beginning.

Note that std::vector::difference_type is a signed integer type (usually std::ptrdiff_t), which is different from size_t; which is an unsigned integer type.

like image 67
songyuanyao Avatar answered Sep 28 '22 15:09

songyuanyao