ValentaTomas
ValentaTomas

Reputation: 270

C-like Array template specialization

How can I write the template for generic array

template <class T, std::size_t N>
struct Data<T[N]> {}

in a way that I can access it's elements by [] operator (or any other way)?

#include <fstream>
#include <iostream>
#include <sstream>
#include <utility>

template <typename T>
struct Data;

template <typename T>
std::ostream& operator<<(std::ostream& os, const Data<T>& val) {
    return val(os);
}

template <typename T>
Data<std::remove_cv_t<T>> data(const T& val) { return { val }; }

template <>
struct Data<int> {
    std::ostream& operator()(std::ostream& os) const {
        os << val;
        return os;
    }
    const int& val;
};

template <class T, std::size_t N>
struct Data<T[N]> {
    std::ostream& operator()(std::ostream& os) const {
        for (std::size_t i = 0; i < N; i++) {
            os << data(val[i]);
        }
        return os;
    }
    T val;
};

Error when accessing:

error: subscripted value is not an array, pointer, or vector
                    os << data(val[i]);
                               ^~~ ~

It seems that I should change <T[N]> for something like <T(&)[N]> to catch reference for the array, but I can't work it out. Or maybe the T val; should be in T* val;, because the array is degenerating to pointer, so I can "catch" it?

EDIT 1

For T val[N]; the error is:

error: cannot initialize an array element of type 'int' with an lvalue of type 'int const[2]'
Data<std::remove_cv_t<T>> data(const T& val) { return { val }; }
                                                    ^~~

EDIT 2

When I try to use

template <typename T, size_t N>
struct Data<std::array<T, N> >

then it's doesn't correspond to any template.

error: implicit instantiation of undefined template 'PrettyPrint::Data<int [2]>'
    sstream << PrettyPrint::data(val);
               ^

Upvotes: 2

Views: 600

Answers (1)

ValentaTomas
ValentaTomas

Reputation: 270

The correct template was

template <typename T, std::size_t N>
struct Data<T[N]> {
    std::ostream& operator()(std::ostream& os) const {
        for (std::size_t i = 0; i < N; i++) {
            os << data(val[i]);
        }
        return os;
    }
    const T(&val)[N];
};

What is the reason for const T(&val)[N];? I'm thinking about catching the reference in contrast to array degeneration to pointer, but I would be really glad if somebody explained it to me in greater depth.

Upvotes: 1

Related Questions