【问题标题】:Compile-time matrix template type编译时矩阵模板类型
【发布时间】:2017-11-04 00:31:18
【问题描述】:

我正在尝试获取我正在编写的一段代码,以便让工作变得有趣。基本上我想生成一个 type,在编译时给出:一个矩阵。

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

谢谢!

【问题讨论】:

  • 您希望矩阵的值成为其类型的一部分?为什么?为什么不简单地abstract_matrix&lt;3, 3, int&gt; id_3by3(vals);
  • 您不想在模板参数列表中传递vals。看看std::initializer_list。它提出了constexpr 的一些问题,尽管它们可能正在修复中。请参阅:stackoverflow.com/questions/15937522/…
  • 是的,您真的不希望元素值成为类型的一部分,因为这将很快导致无法想象的大量模板膨胀,我无缘无故可以想象,或者甚至可能只是在超出某个维度时使编译器崩溃。或许你应该解释一下为什么认为你想要这个,这样你就可以得到更多有用的答案'不要那样做'。
  • @underscore_d,我怀疑这会导致代码臃肿。并非vals 数组的所有值都成为模板定义的一部分。只有vals 的地址成为模板定义的一部分。
  • @RSahu 这对我来说似乎是一个假设,源于问题的模糊性。我的假设恰好不同。

标签: c++ templates


【解决方案1】:

你可以让它工作,但有几件事必须考虑。

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

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

  2. id_3by3的定义需要使用&amp;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 的定义。

【讨论】:

  • 太棒了!如果我把它放在我的标题中,如何避免有多个符号定义?我尝试过 static、const、constexpr 和不同的组合,但要么我无法编译它(非类型模板参数),要么我有多个定义,因此链接器错误。
  • 谢谢!关于这段代码我要给出的唯一警告是,至少对我来说,它可以用 C++17 及更高版本编译。
  • @senseiwa。那很奇怪。我能够使用 g++/C++11 构建程序。
猜你喜欢
  • 2013-11-22
  • 1970-01-01
  • 2014-03-31
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多