I am trying to set up a class for representing 2-3D vectors. It's a template class that takes in a Coord type (integral/flaoting point representation of coordinates) and Dim (number of dimensions) as part of its template definition.
#pragma once
#include <iostream>
#include <array>
#include <type_traits>
#define DIM2 2
#define DIM3 3
typedef size_t Dimensions;
namespace Geo{
template<class Coordinate_type, Dimensions dim = DIM3>
class Vector{
static_assert(std::is_arithmetic<Coordinate_type>::value, "Vector class can only contain Integral or Floating point types");
static_assert(dim >= DIM2, "Vector dimension should be at least 2D");
// friends
// Functions
#if 1
template <class type, Dimensions d>
friend Vector<type, d> CrossProduct(const Vector<type, d>& first, const Vector<type, d>& second);
#else
friend Vector<Coordinate_type, dim> CrossProduct(const Vector<Coordinate_type, dim>& first, const Vector<Coordinate_type, dim>& second);
#endif
std::array<Coordinate_type, dim> coords;
public:
// Constructors
Vector() {}
// Array Constructor
Vector(std::array<Coordinate_type, dim> _coords) : coords(_coords) {}
// 3D explicit constructor
Vector(Coordinate_type _x, Coordinate_type _y, Coordinate_type _z) : coords({_x, _y, _z}) {}
Vector(Coordinate_type _x, Coordinate_type _y) : coords({_x, _y}) {}
inline Vector<Coordinate_type, dim> operator+(const Vector<Coordinate_type, dim>& other);
inline Coordinate_type operator[](const int idx) const;
inline bool operator<(const Vector<Coordinate_type, dim>& other) const;
inline float Magnitude() const;
inline int GetDimension() const;
inline Vector<Coordinate_type, dim> Normalize() const;
};
template<class Coordinate_type, Dimensions dim>
inline Coordinate_type Vector<Coordinate_type, dim>::operator[](int idx) const{
return this->coords[idx];
}
template<class Coordinate_type, Dimensions dim>
inline Vector<Coordinate_type, dim> Vector<Coordinate_type, dim>::operator+(const Vector<Coordinate_type, dim>& other){
}
template<class Coordinate_type, Dimensions dim>
inline int Vector<Coordinate_type, dim>::GetDimension() const{ return this->coords.size(); }
template<class Coordinate_type, Dimensions dim>
inline float Vector<Coordinate_type, dim>::Magnitude() const{
float ret = 0;
for(int i = 0; i < this->coords.size(); i++){
ret += (*this)[i] * (*this)[i];
}
return std::sqrt(ret);
}
template<class Coordinate_type, Dimensions dim>
inline Vector<Coordinate_type, dim> Vector<Coordinate_type, dim>::Normalize() const{
// Store magnitude of vector
Coordinate_type magnitude = this->Magnitude();
// Copy vector
std::array<Coordinate_type, dim> temp;
for(int i = 0; i < this->GetDimension(); i++){
// Store the normalized component
temp[i] = (*this)[i]/magnitude;
}
return Vector<Coordinate_type, dim>(temp);
}
template<class Coordinate_type, Dimensions dim>
inline bool Vector<Coordinate_type, dim>::operator<(const Vector<Coordinate_type, dim>& other) const{
// Call to CrossProduct function
auto crossProd = CrossProduct( this->Normalize(), other.Normalize() );
// other logic ...
return true;
}
template<class Coordinate_type, Dimensions dim>
Vector<Coordinate_type, dim> CrossProduct( const Vector<Coordinate_type, dim>& first, const Vector<Coordinate_type, dim>& second){
// Definition here
return Vector<Coordinate_type, dim> (first.coords[0], first.coords[1], first.coords[2]);
}
}
-----------------------------------------
// main.cpp
int main() {
Geo::Vector<int, 3> v1(1,2,3);
Geo::Vector<int, 3> v2(2,4,6);
if(v1 < v2){
std::cout<< "v1 is less than v2" << std::endl;
}
return 0;
}
It has operator overloads for comparing vectors. And I need to only compare parallel vectors on the basis of their their magnitudes.
To Check for parallelity, I use a cross product. Defined as a friend. But I keep getting an error when I try to call it from the '<' operator overload.
Error reads:
Undefined symbols for architecture arm64: "jmk::CrossProduct(jmk::Vector<int, 3ul> const&, jmk::Vector<int, 3ul> const&)", referenced from: jmk::Vector<int, 3ul>::operator<(jmk::Vector<int, 3ul> const&) const in main.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [main] Error 1
The CrossProduct function is callable from main without any errors but for when it is called from the operator overload. it throws a compilation error.
You don't care of providing a Minimal, Reproducible Example, thus this is a solution with fixing missing parts.
You declare a free friend function. Then you define a function template, and keep the free function undefined. #if 0
enables the code that is like your code and gets the linker error "undefined reference to CrossProduct()
". #if 1
enables the fix.
#include <iostream>
using Dimensions = int;
template <class Coordinate_type, Dimensions dim = 3>
class Vector {
#if 1
template <class type, Dimensions d>
friend Vector<type, d> CrossProduct(const Vector<type, d>& first,
const Vector<type, d>& second);
#else
friend Vector<Coordinate_type, dim> CrossProduct(
const Vector<Coordinate_type, dim>& first,
const Vector<Coordinate_type, dim>& second);
#endif
public:
// Constructors
Vector() {}
// 3D explicit constructor
Vector(Coordinate_type _x, Coordinate_type _y, Coordinate_type _z) {}
inline bool operator<(const Vector<Coordinate_type, dim>& other) const;
};
template <class Coordinate_type, Dimensions dim>
inline bool Vector<Coordinate_type, dim>::operator<(
const Vector<Coordinate_type, dim>& other) const {
// Call to CrossProduct function
auto crossProd = CrossProduct(*this, other);
// other logic ...
return true;
}
template <class Coordinate_type, Coordinate_type dim>
Vector<Coordinate_type, dim> CrossProduct(
const Vector<Coordinate_type, dim>& first,
const Vector<Coordinate_type, dim>& second) {
// Definition here
return first;
}
// main.cpp
int main() {
Vector<int, 3> v1(1, 2, 3);
Vector<int, 3> v2(2, 4, 6);
if (v2 < v1) {
std::cout << "v1 is less than v2" << std::endl;
}
return 0;
}
The life example: https://godbolt.org/z/ExYcjKErM