Я пишу код, в котором мне нужно будет часто переключаться между однородными и декартовыми координатами:
(x, y, z) -> (x, y, z, w = 1)
(x, y, z, w) -> (x/w, y/w, z/w)
Я использую библиотеку, в которой уже есть шаблоны для вектора произвольного размера и типа, а такжекак typedefs для нескольких распространенных, например, так:
typedef vec<3, float> Vec3f;
typedef vec<4, float> Vec4f;
Мне интересно, есть ли способ добавить к этому, чтобы я мог легко переключаться между ними, используя гомогенные <-> декартовы отношенияпоказано выше.Я хотел бы иметь что-то вроде этого:
Vec3f cart1(10, 15, 20);
Vec4f homo1;
homo1 = (Vec4f) cart1;
std::cout << "homo1: " << homo1 << std::endl;
Vec4f homo2(10, 15, 20, 5);
Vec3f cart2;
cart2 = (Vec3f) homo2;
std::cout << "cart2: " << cart2 << std::endl;
Что бы вывести следующее (векторные шаблоны перегружены << операторы для печати): </p>
homo1: 10, 15, 20, 1
cart2: 2, 3, 4
Вот соответствующийКод шаблона из заголовка, обратите внимание, что я добавил часть vec <4, T>:
#include <cmath>
#include <vector>
#include <cassert>
#include <iostream>
template<size_t DimCols,size_t DimRows,typename T> class mat;
template <size_t DIM, typename T> struct vec {
vec() { for (size_t i=DIM; i--; data_[i] = T()); }
T& operator[](const size_t i) { assert(i<DIM); return data_[i]; }
const T& operator[](const size_t i) const { assert(i<DIM); return data_[i]; }
private:
T data_[DIM];
};
/////////////////////////////////////////////////////////////////////////////////
template <typename T> struct vec<3,T> {
vec() : x(T()), y(T()), z(T()) {}
vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
template <class U> vec<3,T>(const vec<3,U> &v);
T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
float norm() { return std::sqrt(x*x+y*y+z*z); }
vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; }
T x,y,z;
};
/////////////////////////////////////////////////////////////////////////////////
// my Vec4f template
template <typename T> struct vec<4,T> {
vec() : x(T()), y(T()), z(T()), w(T()) {}
vec(T X, T Y, T Z) : x(X), y(Y), z(Z), w(1.f) {}
template <class U> vec<4,T>(const vec<4,U> &v);
T& operator[](const size_t i) { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); }
const T& operator[](const size_t i) const { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); }
T x,y,z,w;
};
typedef vec<3, float> Vec3f;
typedef vec<4, float> Vec4f;
Теперь в соответствующем файле .cpp есть код, который уже пытается это сделать, но не для типов, которыеЯ хочу:
template <> template <> vec<3,int> ::vec(const vec<3,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)),z(int(v.z+.5f)) {};
template <> template <> vec<3,float>::vec(const vec<3,int> &v) : x(v.x),y(v.y),z(v.z) {};
Я не совсем понимаю этот макет (часть шаблона <> template <>), но очевидно, что это позволяет приводить между векторами чисел типа int / float, и я подтвердилэтот.Однако, когда я пытался сделать то же самое, я получаю ошибки:
template <> template <> vec<3,float>::vec(const vec<4,float> &v) : x(v.x / v.w),y(v.y / v.w),z(v.z / v.w) {};
template <> template <> vec<4,float>::vec(const vec<3,float> &v) : x(v.x),y(v.y),z(v.z),w(1.f) {};
Компиляция с вышеупомянутым дает это:
tinyrenderer-files/geometry.cpp:9:25: error: template-id ‘vec<>’ for ‘vec<3, float>::vec(const vec<4, float>&)’ does not match any template declaration
template <> template <> vec<3,float>::vec(const vec<4,float> &v) : x(v.x / v.w),y(v.y / v.w),z(v.z / v.w) {};
^~~~~~~~~~~~
In file included from tinyrenderer-files/geometry.cpp:1:0:
tinyrenderer-files/geometry.h:32:30: note: candidates are: constexpr vec<3, float>::vec(vec<3, float>&&)
template <typename T> struct vec<3,T> {
^~~~~~~~
tinyrenderer-files/geometry.h:32:30: note: constexpr vec<3, float>::vec(const vec<3, float>&)
tinyrenderer-files/geometry.h:35:24: note: template<class U> vec<3, T>::vec(const vec<3, U>&) [with U = U; T = float]
template <class U> vec<3,T>(const vec<3,U> &v);
^~~~~~~~
tinyrenderer-files/geometry.h:34:5: note: vec<3, T>::vec(T, T, T) [with T = float]
vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
^~~
tinyrenderer-files/geometry.h:33:5: note: vec<3, T>::vec() [with T = float]
vec() : x(T()), y(T()), z(T()) {}
^~~
tinyrenderer-files/geometry.cpp:10:25: error: template-id ‘vec<>’ for ‘vec<4, float>::vec(const vec<3, float>&)’ does not match any template declaration
template <> template <> vec<4,float>::vec(const vec<3,float> &v) : x(v.x),y(v.y),z(v.z),w(1.f) {};
^~~~~~~~~~~~
In file included from tinyrenderer-files/geometry.cpp:1:0:
tinyrenderer-files/geometry.h:47:30: note: candidates are: constexpr vec<4, float>::vec(vec<4, float>&&)
template <typename T> struct vec<4,T> {
^~~~~~~~
tinyrenderer-files/geometry.h:47:30: note: constexpr vec<4, float>::vec(const vec<4, float>&)
tinyrenderer-files/geometry.h:50:24: note: template<class U> vec<4, T>::vec(const vec<4, U>&) [with U = U; T = float]
template <class U> vec<4,T>(const vec<4,U> &v);
^~~~~~~~
tinyrenderer-files/geometry.h:49:5: note: vec<4, T>::vec(T, T, T) [with T = float]
vec(T X, T Y, T Z) : x(X), y(Y), z(Z), w(1.f) {}
^~~
tinyrenderer-files/geometry.h:48:5: note: vec<4, T>::vec() [with T = float]
vec() : x(T()), y(T()), z(T()), w(T()) {}
^~~
"Не соответствует ни одному объявлению шаблона"кажется очевидной подсказкой, но я не уверен, почему другие строки, которые уже были там, работают, поскольку они, кажется, не объявляют ничего лишнего?
Я надеюсь, что кто-то может помочь:
- Объясните код (template <> template <>), который, кажется, позволяет мне приводить между векторами float / int (который уже присутствовал в библиотеке)
- Объясните, почему код, который я добавилне работает, когда на поверхности это кажется очень похожим
Дайте мне знать, если мне нужно предоставить какие-либо другие фрагменты кода, возможно, там есть что-то, что не выглядит актуальным, но есть.