为什么我需要三个嵌套的花括号来调用赋值运算符,并将const引用到二维数组?

问题描述 投票:1回答:1

我有一个模板类,其赋值运算符的代码如下所示。该赋值运算符接受对二维数组的const左值引用。

template<typename T> 
class matrix{
  ...
template< size_t Nr, size_t Nc>
    matrix& operator=(const T(&arg)[Nr][Nc]) :rows(Nr), cols(Nc) {
        const T* p = &arg[0][0];
        const T* pEnd = p + (Nr * Nc);
        vdata.reserve(sizeof(T) * Nr * Nc);
        std::copy(p, pEnd, std::back_inserter(vdata));
        return *this;
    }
...
size_t rows;
size_t cols;
std::vector<T> vdata;
};

我可以使用以下语法调用此赋值运算符,

matrix<double>& mweights = get reference ...
mweights = {{{ 20.0, 20.0,-10.0},
             {-20.0,-20.0, 30.0}}};

但是,我第一次尝试

mweights = {{ 20.0, 20.0,-10.0},
            {-20.0,-20.0, 30.0}};

导致编译器(选择了C ++ 17标准的MSVC2019)错误消息“ matrix :: operator =':仅在构造函数定义上允许构造函数初始化器列表”在现代C ++中,对象构造和初始化的所有不同方式都可能有点令人困惑(要客气),而且我不确定编译器到底想告诉我什么。但是我发现我非常不开心...

在这种情况下,我期望编译器将带括号的初始化程序视为对二维双精度数组的右值引用,并将赋值运算符的const左值引用参数绑定到该值。显然,我缺少了一些东西(如果这只是冰山一角,也许会丢失很多东西。)

我的问题是1)为什么第一种语法有效?和2)为什么第二个没有?

更新!

感谢Ted注意到我的复制粘贴错误:rows(),cols()这就是编译器消息的全部内容。

因此,同一类还具有采用相同类型参数的模板化构造函数,以及移动分配运算符。因此,当我添加额外的花括号时,我绕过了赋值运算符(因此,编译器停止了抱怨,因为不再实例化模板函数),而是使用模板化的构造函数进行了临时设置,并将其传递给移动赋值运算符!! >

从分配中删除非法成员初始化程序,摆脱了编译器错误,只用两个花括号进行调用就可以了。

我粘贴了其他两个函数,并在下面进行了更正(仅部分原因是因为下面提到的UB仍然存在)分配运算符以供参考。

// ctor for initializing a matrix with syntax 
// auto m = matrix<T>({{1,2,3},{4,5,6}}); or
// auto m = matrix<T>{{{1,2,3},{4,5,6}}};
template< size_t Nr, size_t Nc>
matrix(const T(&arg)[Nr][Nc]) :rows(Nr), cols(Nc) {
    const T* p = &arg[0][0];
    const T* pEnd = p + (Nr * Nc);
    vdata.reserve(sizeof(T) * Nr * Nc);
    std::copy(p, pEnd, std::back_inserter(vdata));
}

//move assignment (cannot be template)
matrix& operator = (matrix&& arg)
{
    // std::cout << "\n matrix move assignment to " << this;
    rows = arg.rows;
    cols = arg.cols;
    vdata = std::move(arg.vdata);
    arg.rows = 0;
    arg.cols = 0;
    return *this;
}
// assignment from arrays.
template< size_t Nr, size_t Nc>
matrix& operator=(const T(&arg)[Nr][Nc]) {
    rows = Nr;
    cols = Nc;   
    const T* p = &arg[0][0];
    const T* pEnd = p + (Nr * Nc);
    vdata.reserve(sizeof(T) * Nr * Nc);
    std::copy(p, pEnd, std::back_inserter(vdata));
    return *this;
}

非常感谢!

我有一个模板类,其赋值运算符的代码如下所示,该赋值运算符接受对二维数组的const左值引用。 template 类矩阵{... template&...

c++
1个回答
0
投票

答案已经在问题的更新部分中。

为了完整性,(并且不要搞砸簿记),我将发布回复。使用{{{},{}}}的第一种语法实际上根本没有使用模板赋值运算符,并且在此过程中隐藏了编译器最初抱怨的语法错误。

© www.soinside.com 2019 - 2024. All rights reserved.