编译时矩阵模板类型

时间:2017-11-02 16:46:01

标签: c++ templates

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

例如,我希望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 * ...;

您对如何<#34; 注入&#34;有任何建议吗?那些值进入模板并在编译时生成一个合适的类型?该类型中的所有内容均为staticconstconstexpr

谢谢!

1 个答案:

答案 0 :(得分:1)

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

  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] { ... };
    
  4. 这是一个工作计划:

    #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的定义。