ankit
ankit

Reputation: 382

How to specialize templated operator overload of template class?

I have a matrix class like this:

template <class Type, size_t x_dim, size_t y_dim>
class mat {
  private:
    std::array<Type, x_dim * y_dim> m_data;
    size_t xdim = x_dim, ydim = y_dim; // xdim=no of cols   ydim= no of rows
public:
    // normal constructor to make unit matrix
     mat() {
        for (int i = 0; i < y_dim; i++)
            for (size_t j = 0; j < x_dim; j++)
                operator()(i, j) = i == j ? 1 : 0;
    }
    
    //constructor to take in array
    mat(const std::array<Type, x_dim * y_dim> &in) {
        assert(in.size() == x_dim * y_dim);
        m_data = in;
    }
    
    // () overload to access elements of matrix
    Type &operator()(const size_t &r, const size_t &c){
        assert(r >= 0 && r < y_dim && c >= 0 && c < x_dim);
        return m_data[r * xdim + c];
    }

    // * overload to multiply two matrices 
    template <size_t lx, size_t ly>
    mat<Type, x_dim, ly> operator*(const mat<Type, lx, ly> &in) const {
        assert(x_dim == ly);
        mat<Type, x_dim, ly> ret;
        int i, j, k;
        for (i = 0; i < y_dim; i++) {
            for (j = 0; j < lx; j++) {
                ret(i, j) = 0;
                for (k = 0; k < x_dim; k++)
                    ret(i, j) += operator()(i, k) * in(k, j);
            }
        }
        return ret;
    }
#ifdef _MSC_VER
    template <>
    mat<Type, xdim, 4> operator*<4,4>(const mat<Type, 4, 4> &in) const;
#endif
};

How do I specialize the operator* function for any mat<Type,4,4> to remove for loops. I tried code below written outside the class defined above:

template <class Type, size_t x_dim, size_t y_dim>
template <size_t lx, size_t ly>
mat<Type, 4, 4> mat<Type, 4, 4>::operator*<4, 4>(const mat<Type, 4, 4> &in) const {
    return mat<Type, 4, 4>({
        operator()(0, 0) * in(0, 0) + operator()(0, 1) * in(1, 0) + operator()(0, 2) * in(2, 0) + operator()(0, 3) * in(3, 0),
        operator()(0, 0) * in(0, 1) + operator()(0, 1) * in(1, 1) + operator()(0, 2) * in(2, 1) + operator()(0, 3) * in(3, 1),
        operator()(0, 0) * in(0, 2) + operator()(0, 1) * in(1, 2) + operator()(0, 2) * in(2, 2) + operator()(0, 3) * in(3, 2),
        operator()(0, 0) * in(0, 3) + operator()(0, 1) * in(1, 3) + operator()(0, 2) * in(2, 3) + operator()(0, 3) * in(3, 3),
        operator()(1, 0) * in(0, 0) + operator()(1, 1) * in(1, 0) + operator()(1, 2) * in(2, 0) + operator()(1, 3) * in(3, 0),
        operator()(1, 0) * in(0, 1) + operator()(1, 1) * in(1, 1) + operator()(1, 2) * in(2, 1) + operator()(1, 3) * in(3, 1),
        operator()(1, 0) * in(0, 2) + operator()(1, 1) * in(1, 2) + operator()(1, 2) * in(2, 2) + operator()(1, 3) * in(3, 2),
        operator()(1, 0) * in(0, 3) + operator()(1, 1) * in(1, 3) + operator()(1, 2) * in(2, 3) + operator()(1, 3) * in(3, 3),
        operator()(2, 0) * in(0, 0) + operator()(2, 1) * in(1, 0) + operator()(2, 2) * in(2, 0) + operator()(2, 3) * in(3, 0),
        operator()(2, 0) * in(0, 1) + operator()(2, 1) * in(1, 1) + operator()(2, 2) * in(2, 1) + operator()(2, 3) * in(3, 1),
        operator()(2, 0) * in(0, 2) + operator()(2, 1) * in(1, 2) + operator()(2, 2) * in(2, 2) + operator()(2, 3) * in(3, 2),
        operator()(2, 0) * in(0, 3) + operator()(2, 1) * in(1, 3) + operator()(2, 2) * in(2, 3) + operator()(2, 3) * in(3, 3),
        operator()(3, 0) * in(0, 0) + operator()(3, 1) * in(1, 0) + operator()(3, 2) * in(2, 0) + operator()(3, 3) * in(3, 0),
        operator()(3, 0) * in(0, 1) + operator()(3, 1) * in(1, 1) + operator()(3, 2) * in(2, 1) + operator()(3, 3) * in(3, 1),
        operator()(3, 0) * in(0, 2) + operator()(3, 1) * in(1, 2) + operator()(3, 2) * in(2, 2) + operator()(3, 3) * in(3, 2),
        operator()(3, 0) * in(0, 3) + operator()(3, 1) * in(1, 3) + operator()(3, 2) * in(2, 3) + operator()(3, 3) * in(3, 3)};    
   }); 
} 

I get this error from intellisense of msvc: enter image description here

and this error from the compiler: 1>Project\Application\include\maths.h(723,34): warning C4346: 'mat<Type,4,4>::*': dependent name is not a type

How do I solve this?

Upvotes: 1

Views: 97

Answers (2)

RedFog
RedFog

Reputation: 1015

temp.spec#temp.expl.spec-16

A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing class template that is explicitly specialized.

Upvotes: 0

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122228

I will use a simpler example:

template <typename T,size_t x>
struct foo {    
    template <size_t y>
    foo<T,x+y> operator*(const foo<T,y>& other){ return {};}
};

You cannot specialize foo::operator* for x==4 without specializing foo. Though, you can supply a non-member operator* and overload it:

#include <iostream>

template <typename T,size_t x> struct foo {};

template <typename T,size_t x,size_t y>
foo<T,x+y> operator*(const foo<T,x>& a,const foo<T,y>& b){ 
    std::cout << "general operator*\n";
    return {};
}

template <typename T>
foo<T,4> operator*(const foo<T,4>& a,const foo<T,4>& b){
    std::cout << "4*4\n";
    return {};
}

int main() {
    foo<int,4> f;
    foo<int,3> g;
    f*f;
    g*g;
}

Output:

4*4
general operator*

Upvotes: 3

Related Questions