Reputation: 1628
Here's the c++ code printing out the buf array, filled with 0, 1, 2, ... 254
#include <iterator>
#include <iostream>
#include <numeric>
int main()
{
int buf[255];
auto it_b = std::begin(buf);
auto it_e = std::end(buf);
std::iota(it_b, it_e, 0);
std::copy(it_b, it_e, std::ostream_iterator<decltype(*it_b)>(std::cout, " "));
std::cout << std::endl;
return 0;
}
I tried to make it generic so there's only one place where the type is explicilty given int
As I need to explicilty declare the type for ostream_iterator
I wonder what is the best way to achieve this.
decltype(*it_b)
decltype(buf[0])
What are the pros/cons of using this or that method?
For this time assume that we are stuck with C-style arrays.
Upvotes: 3
Views: 121
Reputation: 16421
Probably neither of those are what you want - in both cases you're ending up with an lvalue reference to your type, in this case int&
. You could avoid it by using std::decay
, i.e.
std::copy(it_b, it_e, std::ostream_iterator<std::decay_t<decltype(*it_b)>>(std::cout, " "));
The easiest thing to do is to keep the type aliased and use that alias:
using type = int;
type buf[255];
auto it_b = std::begin(buf);
auto it_e = std::end(buf);
std::iota(it_b, it_e, 0);
std::copy(it_b, it_e, std::ostream_iterator<type>(std::cout, " "));
std::cout << std::endl;
This will also work with pathological containers like vector<bool>
, where deducing the type may lead to surprising (and undefined) behavior.
Upvotes: 4
Reputation: 63124
To be rigorously correct, you should use std::iterator_traits
:
std::copy(it_b, it_e, std::ostream_iterator<
typename std::iterator_traits<decltype(it_b)>::value_type
>(std::cout, " "));
One problem with decltype(*it_b)
alone is that it will return a reference in most cases, and that would mess with the outer template that you're instantiating. You could remove the reference by hand, too:
std::copy(it_b, it_e, std::ostream_iterator<
std::remove_reference_t<decltype(*it_b)>
>(std::cout, " "));
Upvotes: 7