Wrath
Wrath

Reputation: 683

Recursive Class Template with overloaded ostream<< operator

I'm trying to implement a simple N-dimensional array. This seems to be working more or less properly but I just can't get its overloaded ostream operator work. Here's my current implementation:

#include <iostream>
#include <memory>
#include <vector>

template <typename Type, int Dimension>
struct Array {
    typedef std::vector<typename Array<Type, Dimension - 1>::type> type;

    template <typename cType, int cDimension>
    friend std::ostream &operator<<(std::ostream &stream, const Array<cType, cDimension>::type &object) {
        if (cDimension == 0) {
            stream << object << ' ';
        } else {
            typedef typename Array<cType, cDimension>::type::iterator ArrayIterator;
            for (ArrayIterator it = object.begin(); it != object.end(); ++it) {
                typedef typename Array<cType, cDimension - 1>::type NestedArray;

                NestedArray nArray = (NestedArray)(*it);
                stream << nArray << std::endl;
            }
        }

        return stream;
    }
};

template <typename Type>
struct Array < Type, 0 > {
    typedef Type type;
};

int main() {
    Array<int, 1>::type c00 = { 1, 2, 3 };
    Array<int, 1>::type c01 = { 2, 3, 4 };
    Array<int, 1>::type c02 = { 3, 4, 5 };
    Array<int, 2>::type c10 = { c00, c01 };
    Array<int, 2>::type c11 = { c01, c02 };
    Array<int, 3>::type c20 = { c10, c11 };

    std::cout << c20 << std::endl;

    return 0;
}

I'm getting the following compilation errors:

1>------ Build started: Project: NDepthArray, Configuration: Debug Win32 ------
1>  Source.cpp
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): warning C4346: 'Array<Type,Dimension>::type' : dependent name is not a type
1>          prefix with 'typename' to indicate a type
1>          c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(25) : see reference to class template instantiation 'Array<Type,Dimension>' being compiled
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): error C2061: syntax error : identifier 'type'
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): error C2805: binary 'operator <<' has too few parameters
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): fatal error C1903: unable to recover from previous error(s); stopping compilation
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I literally tried all my ideas already, which includes removing friend keyword and the actual class parameter but nothing changes. How can we overload operators for such class templates?

Cheers, Joey

Upvotes: 1

Views: 487

Answers (1)

Marco A.
Marco A.

Reputation: 43662

The problem with your approach is that the cType cannot be inferred:

template <typename Type, int Dimension> // Asking for Type as cType
struct Array {
   typedef std::vector<typename Array<Type, Dimension - 1>::type> type;
}

template <typename cType, int cDimension>                     ↓↓↓↓↓
std::ostream &operator<<(std::ostream &stream, typename Array<cType, cDimension>::type &object)

Array<int, 3>::type c20 = { c10, c11 };
std::cout << c20 // Deduction failure

You can find more info here: https://stackoverflow.com/a/12566268/1938163

14.8.2.5/4

In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

As a sidenote: implementing complex structures for multidimensional arrays or vectors with templated recursive code is a not-very-maintainable and surely hard-to-read path to achieve something that could have been done faster, more efficient (less allocations) and clearer with only a contiguous block of memory indexed in different strides.

Upvotes: 2

Related Questions