0

I am currently studying C++ with CLion.

[Problem]

The problem is that the compiler produces linker errors when I tried to implement "matrix_2_2" templated class equipped with various overloaded operators and "triangular" templated function. I have no idea why the linker produces such errors since I did instantiation for every types using extern template phrases in the .h file. I appreciate your help.

"matrix_2_2<double>::operator[](unsigned long)", referenced from:
      _main in main.cpp.o
  "matrix_2_2<double>::operator*=(matrix_2_2<double> const&)", referenced from:
      _main in main.cpp.o
  "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, matrix_2_2<double> const&)", referenced from:
      _main in main.cpp.o
  "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, matrix_2_2<int> const&)", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64

[Information about my class and functions]

"matrix_2_2" (which means 2 x 2 matrix) is a templated class with <typename T>, and has a member variable "element" with type "T *" to store 2 x 2 matrix elements. And I used overloaded operators to implement various matrix and scalar operations.

"triangular" is a templated function which accepts a single int argument, n, and calculate and return n(n+1)/2, of type T.

[Codes]

Below are my C++ codes.

My main.cpp is as follows.

#include "matrix_2_2.h"
#include <iostream>

int main() {
    using namespace std;

    cout << triangular<matrix_2_2<int>>(10) << endl;
    matrix_2_2<double> m1 = 1.1;
    m1[1][0] = -0.125;
    m1[0][0] += 0.5;
    m1 *= triangular<matrix_2_2<double>>(20);
    cout << m1 << endl;
    return 0;
}

My matrix_2_2.h file is as follows.

#ifndef MATRIX_TEMPLATED_MATRIX_2_2_H
#define MATRIX_TEMPLATED_MATRIX_2_2_H

#include <cstddef>
#include <iostream>

using namespace std;

template <typename T>
class matrix_2_2 {
private:
    T *element[2];
public:
    // Default constructor
    matrix_2_2() {element[0] = nullptr; element[1] = nullptr;};
    matrix_2_2(T n) {element[0][0] = n; element[0][1] = 0; element[1][0] = 0; element[1][1] = n;};
    // Operator overloading
    matrix_2_2 &operator+=(matrix_2_2 const &);
    matrix_2_2 operator+(matrix_2_2 const &);
    matrix_2_2 &operator*=(matrix_2_2 const &);
    matrix_2_2 operator*(matrix_2_2 const &);
    matrix_2_2 &operator/=(T const &);
    matrix_2_2 operator/(T const &);
    T *operator[](size_t);

    friend ostream &operator<<(ostream &out, matrix_2_2 const &m);
};

template <typename T> T triangular(int n);

extern template class matrix_2_2<double>;
extern template class matrix_2_2<int>;
extern template class matrix_2_2<short>;
extern template class matrix_2_2<float>;
extern template class matrix_2_2<long>;

extern template int triangular<int>(int);
extern template double triangular<double>(int);
extern template short triangular<short>(int);
extern template float triangular<float>(int);
extern template long triangular<long>(int);
extern template matrix_2_2<int> triangular<matrix_2_2<int>>(int);
extern template matrix_2_2<double> triangular<matrix_2_2<double>>(int);

#endif //MATRIX_TEMPLATED_MATRIX_2_2_H

My overloaded "[]" and "<<" operators, "triangular" functions and some instantiation phrases are as follows.(Which are in the "matrix_2_2.cpp" file.

template class matrix_2_2<double>;
template class matrix_2_2<int>;
template class matrix_2_2<short>;
template class matrix_2_2<float>;
template class matrix_2_2<long>;

template int triangular<int>(int);
template double triangular<double>(int);
template short triangular<short>(int);
template float triangular<float>(int);
template long triangular<long>(int);
template matrix_2_2<int> triangular<matrix_2_2<int>>(int);
template matrix_2_2<double> triangular<matrix_2_2<double>>(int);    

template <typename T>
    T *matrix_2_2<T>::operator[](size_t n) {
        return element[n];
    }
    
    
    template <typename T>
    ostream &operator<<(ostream &out, matrix_2_2<T> const &m) {
        out << "[" << '\t' << m.element[0][0] << '\t' << m.element[0][1] << "]\n";
        out << "[" << '\t' << m.element[1][0] << '\t' << m.element[1][1] << "]\n";
        return out;
    }
    
    
    template <typename T>
    T triangular(int n) {
        T result = n * (n - 1) / 2;
        return result;
    }
Aiden0206
  • 13
  • 3
  • 2
    Don't do explicit instantiations; read [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – molbdnilo Jun 11 '21 at 07:52
  • `operator *=` is declared but never defined. As for `operator<<`, the declaration is wrong, this is a very common error and good compilers warn when they see it. – n. m. could be an AI Jun 11 '21 at 08:15
  • @molbdnilo there's nothing wrong with explicit instantiations. – n. m. could be an AI Jun 11 '21 at 08:18
  • Does this answer your question? [Friend and template in C++](https://stackoverflow.com/questions/48626437/friend-and-template-in-c) – n. m. could be an AI Jun 11 '21 at 08:22
  • Thank you for comments. @n.1.8e9-where's-my-sharem. I defined "operator *=" in my original code. In the post, I only included operators which were indicated by errors. – Aiden0206 Jun 11 '21 at 08:29
  • `operator*=` is in the error messages. If you define it elsewhere, you need to show it. – n. m. could be an AI Jun 11 '21 at 08:53
  • Also `matrix_2_2(T n) {element[0][0] = n; element[0][1] = 0; element[1][0] = 0; element[1][1] = n;};` this constructor is wrong because the array `element` is never initialised. so `element[0]` and `element[1]` are both garbage. – n. m. could be an AI Jun 11 '21 at 08:58

0 Answers0