编译时间矩阵模板类型

Compile-time matrix template type

本文关键字:类型 时间 编译      更新时间:2023-10-16

我正试图获得一段我为工作乐趣而编写的代码。基本上,我想生成一个类型,在编译时给出:一个矩阵。

例如,我希望abstract_matrix如下所示:

template <std::size_t r, std::size_t c, class T = double>
class abstract_matrix
{
public:
static const std::size_t rows = r;
static const std::size_t cols = c;
typedef T value_type;
typedef T storage_type[rows][cols];
constexpr abstract_matrix(storage_type items)
{
// I hope it's not needed
}
storage_type storage;
};

然后,我想用一些魔法来创建具体类型,大致如下:

constexpr static const int vals[3][3] {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
// do magic here for the vals parameter to make this compile
using id_3by3 = abstract_matrix<3, 3, vals, int>;
// use the generated type
id_3by3 mymatrix;
auto matrix = mymatrix * ...;

关于如何将这些值">注入"到模板中并在编译时生成正确的类型,您有什么建议吗?类型中的所有内容都是staticconstconstexpr

谢谢!

您可以让它发挥作用,但有几件事必须考虑。

  1. vals可以作为非类型参数传递。但是,它需要在T之后。否则,参数的基本类型是未知的。

    因此,T没有默认值。您可能会继续将T的默认值设为double,并将最后一个参数的默认值设置为nullptr,但这会导致代码混乱。

  2. id_3by3的定义需要使用&vals,而不仅仅是vals

  3. 如果将vals定义为const,则非类型模板参数的类型中也必须使用const

    const int vals[3][3] { ... };
    

    要求您使用

    template <std::size_t r, std::size_t c, class T, T const(*v)[r][c] >
    class abstract_matrix { ... };
    

    如果你想修改矩阵的内容,你需要使用:

    template <std::size_t r, std::size_t c, class T, T (*v)[r][c]>
    class abstract_matrix { ... };
    

    它要求您使用

    int vals[3][3] { ... };
    

这里有一个工作程序:

#include <iostream>
#include <cstdint>
template <std::size_t r, std::size_t c, class T , T (*v)[r][c]>
class abstract_matrix
{
public:
static const std::size_t rows = r;
static const std::size_t cols = c;
typedef T value_type;
constexpr static T(&vals)[r][c] = *v;
constexpr abstract_matrix()
{
}
};
int vals[3][3] {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
using id_3by3 = abstract_matrix<3, 3, int, &vals>;
int main()
{
id_3by3 mymatrix;
// Original matrix.
for ( size_t i = 0; i < id_3by3::rows; ++i )
{
for ( size_t j = 0; j < id_3by3::cols; ++j )
{
std::cout << id_3by3::vals[i][j] << " ";
id_3by3::vals[i][j]++;
}
std::cout << "n";
}
std::cout << "n";
// Modified matrix.
for ( size_t i = 0; i < id_3by3::rows; ++i )
{
for ( size_t j = 0; j < id_3by3::cols; ++j )
{
std::cout << id_3by3::vals[i][j] << " ";
}
std::cout << "n";
}
}

输出:

1 0 0
0 1 0
0 0 1
2 1 1
1 2 1
1 1 2

更新,以响应OP的命令

当您希望能够定义.h文件类型并在多个.cpp文件中使用它时,可以使用static int vals[3][3] = { ... };

我能够在多个.cpp文件中使用具有以下内容的.h文件。

#pragma once
#include <cstdint>
template <std::size_t r, std::size_t c, class T , T (*v)[r][c]>
class abstract_matrix
{
public:
static const std::size_t rows = r;
static const std::size_t cols = c;
typedef T value_type;
constexpr static T(&vals)[r][c] = *v;
constexpr abstract_matrix()
{
}
};
static int vals[3][3] {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
using id_3by3 = abstract_matrix<3, 3, int, &vals>;

这仍然可以通过将这些行划分为两个.h文件来改进。例如,您可以使用:

abstract_matrix.h:

#pragma once
#include <cstdint>
template <std::size_t r, std::size_t c, class T , T (*v)[r][c]>
class abstract_matrix
{
public:
static const std::size_t rows = r;
static const std::size_t cols = c;
typedef T value_type;
constexpr static T(&vals)[r][c] = *v;
constexpr abstract_matrix()
{
}
};

id_3by3.h:

#include "abstract_matrix.h"
static int vals[3][3] {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
using id_3by3 = abstract_matrix<3, 3, int, &vals>;

这将允许您在不同的.h文件中定义类似于id_3by3的其他类型,而无需在所有文件中复制abstract_matrix的定义。