我问自己,如果知道大小,是否可以在编译时创建单位矩阵。到目前为止,我刚刚编写了一个示例,创建了一个固定大小的基于std :: vector的矩阵,例如: 4×4。但是,我不确定如何设置值。我想,我需要递归:/
// Example program
#include <iostream>
#include <string>
#include <vector>
template <class T>
using vec1D = std::vector<T>;
template <class T>
using vec2D = std::vector<std::vector<T>>;
template <class T, int size>
vec2D<T> make_mat() {
vec2D<T> mat(size, vec1D<T>(size));
return mat;
}
int main()
{
vec2D<float> unit = make_mat<float, 4>();
std::cout
<< unit[0][0] << unit[0][1] << unit[0][2] << unit[0][3] << std::endl
<< unit[1][0] << unit[1][1] << unit[1][2] << unit[1][3] << std::endl
<< unit[2][0] << unit[2][1] << unit[2][2] << unit[2][3] << std::endl
<< unit[3][0] << unit[3][1] << unit[3][2] << unit[3][3] << std::endl;
}
答案 0 :(得分:3)
我问自己,如果知道大小,是否有可能在编译时创建一个单位矩阵。
如果你的矩阵是基于std::vector
,我不这么认为。
但是,如果它基于std::array
并且您希望将其初始化为零(如您的示例中),那么:它是可能的。
// Example program
#include <iostream>
#include <array>
template <typename T, std::size_t D1, std::size_t D2 = D1>
constexpr std::array<std::array<T, D2>, D1> doA ()
{ return { }; }
int main()
{
constexpr auto unit = doA<float, 4U>();
std::cout
<< unit[0][0] << unit[0][1] << unit[0][2] << unit[0][3] << std::endl
<< unit[1][0] << unit[1][1] << unit[1][2] << unit[1][3] << std::endl
<< unit[2][0] << unit[2][1] << unit[2][2] << unit[2][3] << std::endl
<< unit[3][0] << unit[3][1] << unit[3][2] << unit[3][3] << std::endl;
}
但我认为这不是一个好主意:请记住std::array
使用堆栈,而不是堆。所以这个解决方案只适用于很少(很少)的矩阵。
---编辑---
OP(正确)观察
问题是是否可以将矩阵作为单位矩阵初始化:100 010 001
是的,单位矩阵也可以;有点复杂但可能。
// Example program
#include <iostream>
#include <utility>
#include <array>
template <typename T, std::size_t I, std::size_t ... Is>
constexpr auto doU_helper2 (std::index_sequence<Is...> const &)
{ return std::array<T, sizeof...(Is)>
{ { (Is == I ? T{1} : T{0})... } }; }
template <typename T, std::size_t ... Is>
constexpr auto doU_helper1 (std::index_sequence<Is...> const & is)
{ return std::array<std::array<T, sizeof...(Is)>, sizeof...(Is)>
{ { doU_helper2<T, Is>(is)... } }; }
template <typename T, std::size_t Dim>
constexpr auto doU ()
{ return doU_helper1<T>(std::make_index_sequence<Dim>{}); }
int main()
{
constexpr auto unit = doU<float, 4U>();
std::cout
<< unit[0][0] << unit[0][1] << unit[0][2] << unit[0][3] << std::endl
<< unit[1][0] << unit[1][1] << unit[1][2] << unit[1][3] << std::endl
<< unit[2][0] << unit[2][1] << unit[2][2] << unit[2][3] << std::endl
<< unit[3][0] << unit[3][1] << unit[3][2] << unit[3][3] << std::endl;
}
请记住此代码使用的是std::make_index_sequence{}
和std::index_sequence
,这是C ++ 14的功能。
如果你需要一个C ++ 11解决方案,那么创建一个副本并不困难;问你是否需要它(在某个地方我已经完成;我只能检索)。
答案 1 :(得分:2)
您无法在编译时进行动态分配。
您可以在运行时执行此操作。简单的方法是使用循环。
如果你想完全避免循环:
template<std::size_t...Is>
auto index_over(std::index_sequence<Is...>){
return [](auto&&f)->decltype(auto){
return decltype(f)(f)(std::integral_constant<std::size_t,Is>{}...);
};
}
template<std::size_t N>
auto index_upto(std::integral_constant<std::size_t,N> ={}){
return index_over(std::make_index_sequence<N>{});
}
template <class T>
using vec1D = std::vector<T>;
template <class T>
using vec2D = std::vector<std::vector<T>>;
template<std::size_t N, std::size_t I,class T>
vec1D<T> make_row( T const& base, T const& diag ){
return index_upto<I>()([&](auto...Before){
return index_upto<N-I-1>()([&](auto...After)->vec1D<T>{
return {
(void(Before), base)...,
diag,
(void(After), base)...
};
});
});
}
template<std::size_t N, class T>
vec2D<T> make_mat( T const& base, T const& diag){
return index_upto<N>()([&}(auto...Rs)->vec2D<T>{
return {
make_row<N, Rs>(base, diag)...
};
});
}
可能包含拼写错误(写在手机上,未经过测试)。有时会使用有效C ++但g ++ choke的构造;铿锵会理解它。 C ++ 14
索引反而避免必须编写一堆辅助函数来扩展索引参数包;他们让你在lambda中进行扩展。
如果您的编译器抱怨在编译时使用Rs
,请替换为decltype(Rs)::value
- 您的编译器评估失败{/ 1}}。
在C ++ 11中执行此操作很烦人。我可能会使用帮助程序类型来执行包扩展,每个函数我上面写的一个。您还想从C ++ 14重写索引序列。非常好,只是做循环。
constexpr
生成auto u = make_mat<4>( 0, 1 );
的对角矩阵,大小为4x4。
请注意,此技术使用自由int
以及大小调整和类型,可以使用std数组。可悲的是,在C ++ 17之前,lambda不能成为constexpr。
循环解决方案也适用于C ++ 14之后的constexpr
矩阵;你可以改变constexpr中的本地数据。