c++templatesc++20

How to use the template array type of a template class in a template function?


I'm trying to use the array type that I declared within a class that specifies the size. In practice, the class will have several declarations based off the array size, and is only there to help logically group everything together. It could be a namespace if we were allowed to make those templates, and it works in a vacuum.

However, when the user also wants to call this class from a template function, things get messy and I'm wondering how to get everything to play nicely together.


Ideally, I do not want the user directly calling/controlling SubArray's size, as it won't also be exactly "N". And several types will also be built out with N, and used throughout user space. However, type T (int in the example) can be varied throughout and the user can control a lot more freely. Additionally, there will more than just SubArray<T>, ex: SubArray2<T>, SubMatrix<T>, SubTree<T>, etc.

#include <array>

// Originally, the code was tested around something like `Foo`,
// but was translated to `Bar` for more flexibility. 

class Foo {
public:
    static int constexpr CONST_SIZE = 4;
    template <class T>
    using SubArray = std::array<T, CONST_SIZE>;
};

template <int N>
class Bar {
public:
    template <class T>
    using SubArray = std::array<T, N>;
};


void GoodFunc1() {
    Foo::SubArray<int> foo_sub{};
    using MyBar = Bar<4>;
    MyBar::SubArray<int> bar_sub{};
}

template <int N>
void GoodFunc2() {
    Foo::SubArray<int> foo_sub{};
    using MyBar = Bar<4>;
    MyBar::SubArray<int> bar_sub{};
}

template <int N>
void ErrorFunc() {
    Foo::SubArray<int> foo_sub{};
    using MyBar = Bar<N>;
    // MyBar::SubArray<int> bar_sub{};
    // error: expected primary-expression before ‘int’
    // |     MyBar::SubArray<int> bar_sub{};
    // |                     ^~~
}

// This works, but I don't want to make the user initialize every variable like that...
template <int N>
void UglyFunc() {
    Foo::SubArray<int> foo_sub{};
    using MyBar = Bar<N>;
    typename MyBar::template SubArray<int> bar_sub;
}


Solution

  • You could possibly add a helper template:

    template<class T, class U>
    using SubArray = T::template SubArray<U>;
    
    template <int N>
    void NotErrorFuncAnymore() {
        SubArray<Foo, int> foo_sub{};
        // or the original:
        //Foo::SubArray<int> foo_sub{};
    
        using MyBar = Bar<N>;
        SubArray<MyBar, int> bar_sub{};
        // or:
        //SubArray<Bar<N>, int> bar_sub{}; 
    }