I'll start by stating the obvious - while the last change I made in the previous post built, it would blow up in your face if you executed it, because this
&*buffer.end()
is a not-so-good idea. Since
end()
gives you one-past-the-end, dereferencing it will crash immediately (if you're lucky), or will crash during the presentation your soon-to-be-ex-CEO is making to the press on the launch of your brand new service (if you're not). I should've mentioned it, but I forgot to because my goal was not to execute the code, just to get it to build.
Now then, the next step was making sure the types involved were what I was expecting. To that end, I used this:
auto a = &*buffer.begin();
auto b = buffer.begin();
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
VC gave me this:
unsigned __int64 *
class std::_Vector_iterator<class std::_Vector_val<
struct std::_Simple_types<unsigned __int64> > >
So,
uint64*
on one end, and vector<uint64>::iterator
on the other.
GCC gave me this:
Py
N9__gnu_cxx17__normal_iteratorIPySt6vectorIySaIyEEEE
Yep, mangled. No biggie, after going through
c++filt -t
, I got this:unsigned long long*
__gnu_cxx::__normal_iterator<unsigned long long*,
std::vector<unsigned long long, std::allocator<unsigned long long> > >
And there we have it,
ulong long*
on one end, and vector<ulong long>::iterator
on the other.
So, the types were as I was expecting, i.e., there was nothing fancy going on with the types themselves. Which means that my understanding of the dereferencing of iterators was not entirely correct; i.e., iterators may share some traits with pointers (namely, dereferecing), but they're not interchangeable, as far as argument deduction is concerned. Let's see.
#include <vector>
#include <iostream>
void print(int i)
{
std::cout << "int: " << i << std::endl;
}
void print(int* i)
{
std::cout << "int*: " << *i << std::endl;
}
void print(std::vector<int>::iterator i)
{
std::cout << "vector<int>::iterator: " << *i << std::endl;
}
int main() {
std::vector<int> v;
v.push_back(1);
// CALLS void print(int i)
print(v[0]);
auto i = v.begin();
// CALLS void print(std::vector<int>::iterator i).
// IF WE REMOVE THIS FUNCTION, WE GET THE ERROR: NO MATCHING FUNCTION
print(i);
// CALLS void print(int i)
// IF WE HAVE ONLY void print(int* i), THE ERROR IS
// INVALID CONVERSION FROM 'int' TO 'int*'
print(*i);
// THIS CALLS void print(int* i)
print(&*i + 0);
}
In order to get a call to
void print(int* i)
, we must first dereference the iterator (thus, getting an int), and then take its address (the + 0
is optional).
OK, so the solution for the original code is simple. We must change this
template <typename I>
std::pair<double, double> minmax_times(I first, I last, size_t iterations)
{
typedef typename std::iterator_traits<I>::value_type T;
...
std::pair<I, I> m0, m1;
to this
template <typename I>
std::pair<double, double> minmax_times(I first, I last, size_t iterations)
{
typedef typename std::iterator_traits<I>::value_type T;
...
std::pair<T*, T*> m0, m1;
This time, I've built and executed it. It works.
No comments:
Post a Comment