如何初始化 Matrix<T,Rows,Cols> 类型的 constexpr 矩阵?
How to initialise a constexpr matrix of type Matrix<T,Rows,Cols>?
我真的没能总结出问题中的问题。我已经提出了一个类似的问题 。在那里我请求帮助定义 static constexpr
矩阵。解决方案是在模板矩阵列表中添加另一个参数,基本上是 Matrix<T,Rows,Cols,std::make_index_sequence<Rows*Cols>>
。
我接受了答案,但后来我注意到在这个版本中,我的旧代码无法支持调用以 Matrix<T,Rows,Cols>
作为参数的函数,例如:
foo(Matrix<T,Rows,Cols> & foo){...}
因为缺少第四个隐式参数给我一个编译错误,即 candidate template ignored: could not match '__make_integer_seq' against 'integer_sequence'
.
- 有人可以向我解释为什么以及我应该怎么做才能解决
这个?我想它是可以修复的,但我无法弄清楚。
然后我发现我可以用不同的方式定义 class,保持 classic 结构 Matrix<T,Rows,Cols>
,但仍然能够定义 static constexpr
矩阵(我只是在这里添加了必要的内容):
template<typename T, Integer Rows_, Integer Cols_>
class Matrix {
public:
static constexpr Integer Rows=Rows_;
static constexpr Integer Cols=Cols_;
using type= Matrix<T,Rows,Cols>;
using subtype=T;
~Matrix()=default;
Matrix() {}
template<typename...Inputs>
constexpr Matrix (const Inputs&...vals)
: values{{ {static_cast<T>(vals)}...}}
{static_assert(sizeof...(Inputs)==Rows*Cols, "...");}
private:
std::array<T, Rows * Cols> values;
};
因此,使用构造函数中的 static_cast()
,我可以在不更改矩阵 class 模板的情况下定义静态矩阵。我可以做一些事情
static constexpr Matrix< double, 2, 2> A{1.,2.,3.,4.};
但我也可以维护对 foo(Matrix<T,Rows,Cols> & foo){...}
等函数的调用。所以我对这个解决方案没问题。但是后来我尝试创建一个矩阵矩阵,我发现这个 class 版本在这种构造函数中失败了:
Matrix< Matrix<double,1,1>, 2, 2> A{{0.1},{0.1},{0.1},{0.1}};
即使我先初始化元素然后将它们作为参数传递也会成功:
static constexpr Matrix< double, 1,1> a{{0.1}};
static constexpr Matrix< Matrix<double,1,1>, 2, 2> A{a,a,a,a};
但是,如果可能的话,我想避免这种情况。
作为一个更清楚的例子,我将给出这个:
Matrix< Matrix<Real,1,1>, 2, 2> A{a,a,a,{0.1}};
这给出了以下编译错误:
candidate template ignored: substitution failure : deduced incomplete pack <Matrix<double, 1, 1>, Matrix<double, 1, 1>, Matrix<double, 1, 1>,
(no value)> for template parameter 'Inputs'``` (so ```{0.1}``` is no value).
如果我编写构造函数 Matrix<double,1,1>{0.1}
而不是 {0.1}
,那么它可以工作,但看起来很可怕。
- 为什么我不能简单地构造矩阵的元素
{0.1}
系列?有什么解决方法吗?
- Can someone, please, explain to me why and what should I do to fix this? I guess it is fixable but I was not able to figure it out.
我无法解释。
我可以确认 clang++ 给出了错误,但是 g++ 编译没有问题。我怀疑是 clang++ 错误(或不符合标准),但我不是专家。我打算将问题简化并作为一个单独的问题提出。
如何解决?您可以添加一个继承级别。
您可以创建一个 Matrix_base
class 来实现 std::make_index_sequence
/std::index_sequence
template <typename, typename>
class Matrix_base;
template <typename T, std::size_t ... Is>
class Matrix_base<T, std::index_sequence<Is...>>
{
// values_ and constructors
};
并从 Matrix
class 继承它,只有三个模板参数
template <typename T, std::size_t NR, std::size_t NC>
class Matrix : public Matrix_base<T, std::make_index_sequence<NR*NC>>
{
public:
using value_type = T;
using MB = Matrix_base<T, std::make_index_sequence<NR*NC>>;
using MB::MB;
using MB::values_;
// other methods
};
下面是一个完整的例子
Why cannot I simply construct the elements of the matrix by means of the series of {0.1}? Is there any workaround for this?
问题是类型推导。
如果你有构造函数
template<typename...Inputs>
constexpr Matrix (const Inputs&...vals)
: values{{ {static_cast<T>(vals)}...}}
{static_assert(sizeof...(Inputs)==Rows*Cols, "...");}
接收一个可变序列的 Input...
参数,其中编译器 必须 推导 Inputs...
类型从 vals...
值中,您不能将某些东西作为 {0.1}
(或者可能是 {0.1, 0.2, 0.3, 0.4}
)作为希望编译器可以从中推断出类型的值传递。
如果你有原始构造函数则不同
constexpr Matrix (getType<value_type, Is> ... vals)
: values_{{vals...}}
{}
其中 getType<value_type, Is>
变为 value_type
。您有一个构造函数,它需要一系列 sizeof...(Is)
个已知类型的元素:value_type
。因此无需推导类型:当 Matrix
构造函数期望类型为 Matrix<double, 1u, 1u>
的四个元素时,如果您传递四个参数 {0.1}
(或者还有四个 0.1
),编译器知道{0.1}
必须用于初始化 Matrix<double, 1u, 1u>
.
下面是一个完整的编译C++14的例子
#include <array>
#include <type_traits>
template <typename T, std::size_t>
using getType = T;
template <typename, typename>
class Matrix_base;
template <typename T, std::size_t ... Is>
class Matrix_base<T, std::index_sequence<Is...>>
{
protected:
std::array<T, sizeof...(Is)> values_{};
public:
constexpr Matrix_base (getType<T, Is> ... vals)
: values_{{vals...}}
{}
constexpr Matrix_base (std::array<T, sizeof...(Is)> const & a)
: values_{a}
{}
constexpr Matrix_base (std::array<T, sizeof...(Is)> && a)
: values_{std::move(a)}
{}
constexpr Matrix_base () = default;
~Matrix_base() = default;
constexpr Matrix_base (Matrix_base const &) = default;
constexpr Matrix_base (Matrix_base &&) = default;
constexpr Matrix_base & operator= (Matrix_base const &) = default;
constexpr Matrix_base & operator= (Matrix_base &&) = default;
};
template <typename T, std::size_t NR, std::size_t NC>
class Matrix : public Matrix_base<T, std::make_index_sequence<NR*NC>>
{
public:
using value_type = T;
using MB = Matrix_base<T, std::make_index_sequence<NR*NC>>;
using MB::MB;
using MB::values_;
constexpr T const & operator() (std::size_t r, std::size_t c) const
{ return values_[r*NC+c]; }
T & operator() (std::size_t r, std::size_t c)
{ return values_[r*NC+c]; }
constexpr std::size_t rows () const
{ return NR; }
constexpr std::size_t columns () const
{ return NC; }
};
template <typename T, std::size_t Dim1, std::size_t Dim2>
void foo (Matrix<T, Dim1, Dim2> const &)
{ }
int main()
{
static constexpr Matrix<double,2,2> staticmat{0.1,0.2,0.3,0.4};
Matrix<Matrix<double,1,1>, 2, 2> a{{0.1}, {0.1}, {0.1}, {0.1}};
Matrix<Matrix<double,1,1>, 2, 2> b{0.1, 0.1, 0.1, 0.1};
foo(staticmat);
foo(a);
foo(b);
}
我真的没能总结出问题中的问题。我已经提出了一个类似的问题 static constexpr
矩阵。解决方案是在模板矩阵列表中添加另一个参数,基本上是 Matrix<T,Rows,Cols,std::make_index_sequence<Rows*Cols>>
。
我接受了答案,但后来我注意到在这个版本中,我的旧代码无法支持调用以 Matrix<T,Rows,Cols>
作为参数的函数,例如:
foo(Matrix<T,Rows,Cols> & foo){...}
因为缺少第四个隐式参数给我一个编译错误,即 candidate template ignored: could not match '__make_integer_seq' against 'integer_sequence'
.
- 有人可以向我解释为什么以及我应该怎么做才能解决 这个?我想它是可以修复的,但我无法弄清楚。
然后我发现我可以用不同的方式定义 class,保持 classic 结构 Matrix<T,Rows,Cols>
,但仍然能够定义 static constexpr
矩阵(我只是在这里添加了必要的内容):
template<typename T, Integer Rows_, Integer Cols_>
class Matrix {
public:
static constexpr Integer Rows=Rows_;
static constexpr Integer Cols=Cols_;
using type= Matrix<T,Rows,Cols>;
using subtype=T;
~Matrix()=default;
Matrix() {}
template<typename...Inputs>
constexpr Matrix (const Inputs&...vals)
: values{{ {static_cast<T>(vals)}...}}
{static_assert(sizeof...(Inputs)==Rows*Cols, "...");}
private:
std::array<T, Rows * Cols> values;
};
因此,使用构造函数中的 static_cast()
,我可以在不更改矩阵 class 模板的情况下定义静态矩阵。我可以做一些事情
static constexpr Matrix< double, 2, 2> A{1.,2.,3.,4.};
但我也可以维护对 foo(Matrix<T,Rows,Cols> & foo){...}
等函数的调用。所以我对这个解决方案没问题。但是后来我尝试创建一个矩阵矩阵,我发现这个 class 版本在这种构造函数中失败了:
Matrix< Matrix<double,1,1>, 2, 2> A{{0.1},{0.1},{0.1},{0.1}};
即使我先初始化元素然后将它们作为参数传递也会成功:
static constexpr Matrix< double, 1,1> a{{0.1}};
static constexpr Matrix< Matrix<double,1,1>, 2, 2> A{a,a,a,a};
但是,如果可能的话,我想避免这种情况。
作为一个更清楚的例子,我将给出这个:
Matrix< Matrix<Real,1,1>, 2, 2> A{a,a,a,{0.1}};
这给出了以下编译错误:
candidate template ignored: substitution failure : deduced incomplete pack <Matrix<double, 1, 1>, Matrix<double, 1, 1>, Matrix<double, 1, 1>,
(no value)> for template parameter 'Inputs'``` (so ```{0.1}``` is no value).
如果我编写构造函数 Matrix<double,1,1>{0.1}
而不是 {0.1}
,那么它可以工作,但看起来很可怕。
- 为什么我不能简单地构造矩阵的元素
{0.1}
系列?有什么解决方法吗?
- Can someone, please, explain to me why and what should I do to fix this? I guess it is fixable but I was not able to figure it out.
我无法解释。
我可以确认 clang++ 给出了错误,但是 g++ 编译没有问题。我怀疑是 clang++ 错误(或不符合标准),但我不是专家。我打算将问题简化并作为一个单独的问题提出。
如何解决?您可以添加一个继承级别。
您可以创建一个 Matrix_base
class 来实现 std::make_index_sequence
/std::index_sequence
template <typename, typename>
class Matrix_base;
template <typename T, std::size_t ... Is>
class Matrix_base<T, std::index_sequence<Is...>>
{
// values_ and constructors
};
并从 Matrix
class 继承它,只有三个模板参数
template <typename T, std::size_t NR, std::size_t NC>
class Matrix : public Matrix_base<T, std::make_index_sequence<NR*NC>>
{
public:
using value_type = T;
using MB = Matrix_base<T, std::make_index_sequence<NR*NC>>;
using MB::MB;
using MB::values_;
// other methods
};
下面是一个完整的例子
Why cannot I simply construct the elements of the matrix by means of the series of {0.1}? Is there any workaround for this?
问题是类型推导。
如果你有构造函数
template<typename...Inputs>
constexpr Matrix (const Inputs&...vals)
: values{{ {static_cast<T>(vals)}...}}
{static_assert(sizeof...(Inputs)==Rows*Cols, "...");}
接收一个可变序列的 Input...
参数,其中编译器 必须 推导 Inputs...
类型从 vals...
值中,您不能将某些东西作为 {0.1}
(或者可能是 {0.1, 0.2, 0.3, 0.4}
)作为希望编译器可以从中推断出类型的值传递。
如果你有原始构造函数则不同
constexpr Matrix (getType<value_type, Is> ... vals)
: values_{{vals...}}
{}
其中 getType<value_type, Is>
变为 value_type
。您有一个构造函数,它需要一系列 sizeof...(Is)
个已知类型的元素:value_type
。因此无需推导类型:当 Matrix
构造函数期望类型为 Matrix<double, 1u, 1u>
的四个元素时,如果您传递四个参数 {0.1}
(或者还有四个 0.1
),编译器知道{0.1}
必须用于初始化 Matrix<double, 1u, 1u>
.
下面是一个完整的编译C++14的例子
#include <array>
#include <type_traits>
template <typename T, std::size_t>
using getType = T;
template <typename, typename>
class Matrix_base;
template <typename T, std::size_t ... Is>
class Matrix_base<T, std::index_sequence<Is...>>
{
protected:
std::array<T, sizeof...(Is)> values_{};
public:
constexpr Matrix_base (getType<T, Is> ... vals)
: values_{{vals...}}
{}
constexpr Matrix_base (std::array<T, sizeof...(Is)> const & a)
: values_{a}
{}
constexpr Matrix_base (std::array<T, sizeof...(Is)> && a)
: values_{std::move(a)}
{}
constexpr Matrix_base () = default;
~Matrix_base() = default;
constexpr Matrix_base (Matrix_base const &) = default;
constexpr Matrix_base (Matrix_base &&) = default;
constexpr Matrix_base & operator= (Matrix_base const &) = default;
constexpr Matrix_base & operator= (Matrix_base &&) = default;
};
template <typename T, std::size_t NR, std::size_t NC>
class Matrix : public Matrix_base<T, std::make_index_sequence<NR*NC>>
{
public:
using value_type = T;
using MB = Matrix_base<T, std::make_index_sequence<NR*NC>>;
using MB::MB;
using MB::values_;
constexpr T const & operator() (std::size_t r, std::size_t c) const
{ return values_[r*NC+c]; }
T & operator() (std::size_t r, std::size_t c)
{ return values_[r*NC+c]; }
constexpr std::size_t rows () const
{ return NR; }
constexpr std::size_t columns () const
{ return NC; }
};
template <typename T, std::size_t Dim1, std::size_t Dim2>
void foo (Matrix<T, Dim1, Dim2> const &)
{ }
int main()
{
static constexpr Matrix<double,2,2> staticmat{0.1,0.2,0.3,0.4};
Matrix<Matrix<double,1,1>, 2, 2> a{{0.1}, {0.1}, {0.1}, {0.1}};
Matrix<Matrix<double,1,1>, 2, 2> b{0.1, 0.1, 0.1, 0.1};
foo(staticmat);
foo(a);
foo(b);
}