woockashek
woockashek

Reputation: 1628

Detecting type of data in c++ array

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.

  1. decltype(*it_b)
  2. decltype(buf[0])
  3. something other ...

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

Answers (2)

krzaq
krzaq

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

Quentin
Quentin

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

Related Questions