C++模板化结构转换

pdtvr36n  于 2023-06-07  发布在  其他
关注(0)|答案(1)|浏览(109)

我试图开发自己的三维渲染器,我需要一个三维矢量结构。要做到这一点,我需要得到一个Vector<3,double>,将其乘以一个4x 4矩阵,然后将其转换为Vector<2,int>,表示屏幕上像素的坐标。

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;
}

但当我尝试这样做时:

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;
}

我得到这个错误:

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)
      |     ^~~~~~~~

这是什么意思?如何避免这个错误?谢谢!

z9smfwbn

z9smfwbn1#

const Vec<DIM, T> &v-这是对常量向量的引用。
T &operator[](size_t idx)-这是一个非常数向量的下标运算符。
添加另一个重载的下标运算符const T &operator[](size_t idx) const-这是一个常量向量的下标运算符:

T &operator[](size_t idx)
    {
        return data[idx];
    }

使用C++23中的Explicit对象参数(推导this),您将能够将两个下标运算符替换为一个:

auto &&operator[](this auto&& self, size_t idx)
    {
        return self.data[idx];
    }

GCC和Clang还不支持这个C+23特性,MSVC支持/std:c++latest,但不支持/std:c++23https://godbolt.org/z/onr7GK6x5。查看编译器支持的功能: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)
      |     ^~~~~~~~

该错误说明:对于const Vec<DIM, T> &vv函数成员中的thisconst Vec<DIM, T> *this,并且T &operator[](size_t idx)不能用于常量向量对象。

相关问题