C++:犰狳列矩阵初始化不明确
C++: Armadillo column matrix initialization ambiguous
我定义了一个犰狳矩阵,并尝试根据其 manual.
通过初始化列表对其进行初始化
没关系,除非我尝试定义一个列矩阵。
为什么会模棱两可?
#include <armadillo>
int main()
{
// ok : square matrix
arma::mat A={{1.0,2.0},{3.0,4.5}};
// ok: row matrix
arma::mat B={3.5,4.0};
// error: conversion from ‘<brace-enclosed initializer list>’ to
// ‘arma::mat {aka arma::Mat<double>}’ is ambiguous
arma::mat C={{3.5},{4.0}};
// ok: column matrix
arma::mat D=arma::mat({3.5,4.0}).t();
return 0;
}
我想这与 C++ 中的数组定义有关,而不是 Armadillo。
看来您正在按数组初始化矩阵。因此,您的正确值必须是 C++ 标准的确定数组。让我们看看您的第三个定义的正确值:
{{3.5},{4.0}}
这并不意味着第一行为 3.5,第二行为 4.0 的 1*2 列矩阵。它代表任何矩阵,其中两行分别以 3.5 和 4.0 开头。你可能偶尔看到过这样的定义:
double d_array[2][6] = {{3.5},{4.0}};
只有 d_array
中每一行的第零个元素被初始化。由于此右值可以赋予任何具有两行或更多行的二维数组,因此它是不确定的,不能赋予矩阵初始化器。
我不确定它是否有意义,如果有任何不正确的地方,请通过在下面评论这个答案来通知我。
简单回答:标准规范的规则。
首先,您的声明
arma::mat C={{3.5},{4.0}};
复制初始化一个对象C
。(复制初始化不一定调用复制构造函数)
初始化程序是 initializer-list,并且使用 list-initialization。
因为对象 C
是 class,所以首先搜索 initializer-list construtor。
armadillo::Mat<eT>
有两个 initializer-list constructor:
// defined in "<include-dir>/armadillo_bits/Mat_bones.hpp"
Mat(const std::initializer_list<eT>& list);
Mat(const std::initializer_list< std::initializer_list<eT> >& list);
这些是重载决策中的候选函数。
为了确定最佳可行函数,考虑了从 initializer-list 到每个参数的隐式转换的偏序。在这种情况下,使用 list-initialization sequence。 {3.5}
和{4.0}
都可以转换为eT
和std::initializer_list<eT>
。这里的重点是两种情况都有隐式转换。规范定义了这种转换有最差的顺序,这两个构造函数是最差的,换句话说,相同的顺序导致不明确的重载决议。
这是 C++11/14 标准的问题。因为每个内部集合中只有一个元素,所以标准本质上说 {{3.5},{4.0}}
也可以解释为 {3.5,4.0}
。也就是说,{3.5}
可以隐式转换为double(3.5)
。这就导致了两个构造函数之间的歧义。
一种可能的解决方案是使用 Armadillo 列向量构造函数:
arma::mat C = arma::colvec( {3.5, 4.0} );
我定义了一个犰狳矩阵,并尝试根据其 manual.
通过初始化列表对其进行初始化没关系,除非我尝试定义一个列矩阵。
为什么会模棱两可?
#include <armadillo>
int main()
{
// ok : square matrix
arma::mat A={{1.0,2.0},{3.0,4.5}};
// ok: row matrix
arma::mat B={3.5,4.0};
// error: conversion from ‘<brace-enclosed initializer list>’ to
// ‘arma::mat {aka arma::Mat<double>}’ is ambiguous
arma::mat C={{3.5},{4.0}};
// ok: column matrix
arma::mat D=arma::mat({3.5,4.0}).t();
return 0;
}
我想这与 C++ 中的数组定义有关,而不是 Armadillo。
看来您正在按数组初始化矩阵。因此,您的正确值必须是 C++ 标准的确定数组。让我们看看您的第三个定义的正确值:
{{3.5},{4.0}}
这并不意味着第一行为 3.5,第二行为 4.0 的 1*2 列矩阵。它代表任何矩阵,其中两行分别以 3.5 和 4.0 开头。你可能偶尔看到过这样的定义:
double d_array[2][6] = {{3.5},{4.0}};
只有 d_array
中每一行的第零个元素被初始化。由于此右值可以赋予任何具有两行或更多行的二维数组,因此它是不确定的,不能赋予矩阵初始化器。
我不确定它是否有意义,如果有任何不正确的地方,请通过在下面评论这个答案来通知我。
简单回答:标准规范的规则。
首先,您的声明
arma::mat C={{3.5},{4.0}};
复制初始化一个对象C
。(复制初始化不一定调用复制构造函数)
初始化程序是 initializer-list,并且使用 list-initialization。
因为对象 C
是 class,所以首先搜索 initializer-list construtor。
armadillo::Mat<eT>
有两个 initializer-list constructor:
// defined in "<include-dir>/armadillo_bits/Mat_bones.hpp"
Mat(const std::initializer_list<eT>& list);
Mat(const std::initializer_list< std::initializer_list<eT> >& list);
这些是重载决策中的候选函数。
为了确定最佳可行函数,考虑了从 initializer-list 到每个参数的隐式转换的偏序。在这种情况下,使用 list-initialization sequence。 {3.5}
和{4.0}
都可以转换为eT
和std::initializer_list<eT>
。这里的重点是两种情况都有隐式转换。规范定义了这种转换有最差的顺序,这两个构造函数是最差的,换句话说,相同的顺序导致不明确的重载决议。
这是 C++11/14 标准的问题。因为每个内部集合中只有一个元素,所以标准本质上说 {{3.5},{4.0}}
也可以解释为 {3.5,4.0}
。也就是说,{3.5}
可以隐式转换为double(3.5)
。这就导致了两个构造函数之间的歧义。
一种可能的解决方案是使用 Armadillo 列向量构造函数:
arma::mat C = arma::colvec( {3.5, 4.0} );