C++ - 用逗号分隔的值初始化矩阵

7

你好,我看到了这个代码。它演示了如何使用dlib库的矩阵结构。

根据这个代码,可以通过以下方式初始化矩阵结构:

M = 54.2,  7.4,  12.1,
    1,     2,    3,
    5.9,   0.05, 1;

在C++中,这怎么可能实现呢?

这是某种运算符重载吗?


12
为了您读者的健康,我建议您不要尝试模仿这个可怕的东西。我建议使用 std::initialiser_list,给出M = {...}; - Mike Seymour
1个回答

13

逻辑

通过重载operator, (逗号运算符),可以实现这一点,例如将其用于将新的浮点值推送到M中。

需要注意的一点是,operator, 应该始终至少具有一个类类型参数,因此您需要创建一个隐式可转换为浮点值的类(例如通过具有 1 个类型为 doublefloat 的非 explicit 构造函数)。

示例

例如,我们将尝试对覆盖一个 std::vector 的包装类型进行此操作,并尝试使 M = 1, 2, 3, 4, 5 成为一个有效表达式,其中结果是一个按顺序包含这些元素的 std::vector。您会发现这很容易适用于您提供的矩阵示例。

需要记住的一点是,operator= 的优先级高于 operator,(如此运算符优先级表格所示);因此,M = 1, 2, 3, 4, 5 实际上会被解析为:(((((M = 1), 2), 3), 4), 5)

鉴于此,我们将从创建具有一个接受单个值并将其推送到容器中的 container 类的 operator= 开始:

template<typename ValueType>
struct container {
    
    explicit container(std::size_t n) {
        vec.reserve(n);
    }
    
    container& operator=(ValueType a) {
        vec.push_back(a);
        return (*this);
    }

    std::vector<ValueType> vec;
    
};

在这一点上,我们可以将operator定义为:

template<typename ValueType>
container<ValueType>& operator,(container<ValueType>& m, ValueType a) {
    m.vec.push_back(a);
    return m;
}

它只是推回一个新的元素值。

现在你可以轻松地看到以下代码可以正常工作并打印出1 2 3 4 5

int main() {
    container<int> M(5);
    M = 1, 2, 3, 4, 5;
    for (auto i : M.vec) std::cout << i << ' ';
}

实时演示

注意事项

我尽可能地不赞成使用这种技术。它会强制你对其他运算符(例如operator=)进行奇怪的语义设计,似乎并没有为简单使用std::initializer_list<T>增加任何东西。

一个更合理的示例是将operator=定义如下:

container& operator=(std::initializer_list<ValueType> a) {
    std::copy(begin(a), end(a), back_inserter(vec)); 
    return (*this);
}

然后只需使用方括号:

int main() {
    container<int> M(5);
    M = { 1, 2, 3, 4, 5 };
    for (auto i : M.vec) std::cout << i << ' ';
}

实时演示


1
@RuggeroTurra 它被传递给对象M的构造函数,在matrix<double> M(3,3);的初始化中。 - Shoe
这就是为什么C语言的人讨厌C++的原因。 - paulm
4
这也是为什么C++开发者讨厌那些重载了逗号运算符的人编写的C++代码。 - eerorika
@Nfys 很高兴听到这个消息!顺便说一下,我已经更新了我的答案,以给出更深入的示例。 - Shoe
顺便提一下,Eigen使用这种初始化方式,虽然使用提取运算符,比如 M << 1,2,3,4,5,6;。我也不是很喜欢这种方式。 - vsoftco
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接