I am trying to develop my own 3d renderer, and I need a 3D vector struct for this. To do this, I need to get a Vector<3, double>, multiply it to a 4x4 matrix, and then convert it to a Vector<2, int> that represents the coordinates of the pixel on the screen.
template <size_t DIM, typename T>
struct Vec
{
// Vector components
T data[DIM];
Vec() : data() {}
Vec(std::vector<T> _data)
{
assert(_data.size() == DIM);
for (int i = DIM; i--; data[i] = _data[i])
;
}
// Convert Vec<DIM, T> -> Vec<DIM, U>
template <typename U>
Vec(Vec<DIM, U> &v)
{
for (int i = 0; i < DIM; i++)
data[i] = (T)v[i];
}
T &operator[](size_t idx)
{
return data[idx];
}
};
template <size_t LEN, size_t DIM, typename T>
Vec<LEN, T> embed(const Vec<DIM, T> &v, T fill = 1)
{
Vec<LEN, T> ret;
for (size_t i = LEN; i--; ret[i] = (i < DIM ? v[i] : fill))
;
return ret;
}
template <size_t LEN, size_t DIM, typename T>
Vec<LEN, T> proj(const Vec<DIM, T> &v)
{
Vec<LEN, T> ret;
for (size_t i = LEN; i--; ret[i] = v[i])
;
return ret;
}
But when I try to do this:
int main()
{
Vec<3, float> x({0.8, 4.3, 3.3});
Vec<4, float> v0 = embed<4>(x);
Vec<2, float> v1 = proj<2>(v0);
Vec<2, int> y = (Vec<2, int>)(v1);
std::cout << x[0] << '\n';
std::cout << y[0] << '\n';
return 0;
}
I get this error:
main.cpp: In instantiation of ‘Vec<LEN, T> embed(const Vec<DIM, T>&, T) [with long unsigned int LEN = 4; long unsigned int DIM = 3; T = float]’:
main.cpp:55:31: required from here
main.cpp:38:49: error: passing ‘const Vec<3, float>’ as ‘this’ argument discards qualifiers [-fpermissive]
38 | for (size_t i = LEN; i--; ret[i] = (i < DIM ? v[i] : fill))
| ~^
main.cpp:28:5: note: in call to ‘T& Vec<DIM, T>::operator[](size_t) [with long unsigned int DIM = 3; T = float; size_t = long unsigned int]’
28 | T &operator[](size_t idx)
| ^~~~~~~~
What does this mean? How can I avoid this error? Thanks!
const Vec<DIM, T> &v
- this is a reference to a constant vector.
T &operator[](size_t idx)
- this is a subscript operator of a non constant vector.
Add yet another, overloaded subscript operator const T &operator[](size_t idx) const
- this is a subscript operator of a constant vector:
T &operator[](size_t idx)
{
return data[idx];
}
With the Explicit object parameter (deducing this
) in C++23 you will be able to replace that two subscript operators with a single one:
auto &&operator[](this auto&& self, size_t idx)
{
return self.data[idx];
}
This C+23 feature is not supported yet by GCC and Clang, MSVC supports it with /std:c++latest
but not with /std:c++23
: https://godbolt.org/z/onr7GK6x5.
See the supported features by the compilers: C++23 core language features.
main.cpp:38:49: error: passing ‘const Vec<3, float>’ as ‘this’ argument discards qualifiers [-fpermissive]
38 | for (size_t i = LEN; i--; ret[i] = (i < DIM ? v[i] : fill))
| ~^
main.cpp:28:5: note: in call to ‘T& Vec<DIM, T>::operator[](size_t) [with long unsigned int DIM = 3; T = float; size_t = long unsigned int]’
28 | T &operator[](size_t idx)
| ^~~~~~~~
The error explains: for const Vec<DIM, T> &v
, this
in v
functional members is const Vec<DIM, T> *this
, and T &operator[](size_t idx)
may not be used with constant vector objects.