【问题标题】:Proper template idiom (intuition)正确的模板习语(直觉)
【发布时间】:2021-06-16 22:28:11
【问题描述】:

我试图从更深层次的概念中理解 C++ 模板元编程。我不明白的是模板的真正含义。具体来说,具有静态成员的模板类的习语是什么。举个例子:

template <class T>
class Matrix {
  private:
    
  public:
    static constexpr Matrix<T> Identity(int,int);
    static constexpr Matrix<T> Zero(int,int);
    static constexpr Matrix<T> Null = Matrix();

    typdef value_type;

    Matrix();
    Matrix(int,int);
}

Matrix 的静态成员函数显然构造了典型的矩阵。我的想法是思考文本(习语)Matrix&lt;T&gt;::Identity 的方式将是 一个类的身份矩阵 value_type = T

TL;DR

重申一下,我相信上面的模板会生成一组 类,其中包含各自的“类型”静态成员 Matrix&lt;T&gt;::Identity。这与一些Matrix::Identity&lt;T&gt;() 的其他直观语义相比,这将是所有矩阵的T 类型的标识。哪个是正确的?

【问题讨论】:

  • 模板就是食谱。当您执行Matrix&lt;int&gt; 时,它会获取您的模板并标记一个版本,在该版本中它将所有出现的T 替换为int
  • 我不知道这被称为成语。它就像一个带有静态方法的普通类,只是你可以从模板中实例化许多不同的类
  • Matrix 是一个类模板。对于给定的TMatrix&lt;T&gt; 是一个类。 Matrix&lt;T&gt;::Identity 是类Matrix&lt;T&gt; 的静态类函数,Matrix&lt;T&gt;::Null 是类的静态成员。 Matrix::Identity&lt;T&gt; 不是一个东西,尽管可以有非模板类的模板成员,并且它们会有那种语法。
  • TY,编辑了评论。
  • @molbdnilo“并非所有模板编程都是元编程”?一些模板编程当然是元 ;)

标签: c++ class templates member


【解决方案1】:

没有任何其他条件,Matrix&lt;T&gt;::identityMatrix::identity&lt;T&gt; 没有什么不同。它看起来就像someFunction&lt;T&gt;。所以没有成语。

但另一方面,很多实际问题会让你选择更好的。

  1. Matrix::identity&lt;T&gt; 是什么?如果Matrix&lt;T&gt; 表示其元素类型为T 的矩阵类,那么Matrix 本身是什么?它是一个类模板,所以没有实例化就不能有任何成员。在这种情况下,您应该定义一个单独的类(例如,名为MatrixUtility),并使用MatrixUtility::identity&lt;T&gt;。听起来很吵吧?

  2. 但是,Matrix::identity(或MatrixUtility::identity)呢?通常T 类型可以在上下文中推导出来。例如:

Matrix<int> a = MatrixUtility::identity(3, 3); // T=int is required in this context.
auto lambda = [](Matrix<double>){};
lambda(MatrixUtility::identity(2, 2)); // T=double is required in this context.

所以有一个棘手的方法来实现它,通过operator T()的自动推断:

struct Helper{
    template<typename T>
    operator Matrix<T>(){
        // construct and return
    };
    int w, h;
};

struct MatrixUtility{
    Helper identity(int w, int h){
        return Helper{ w, h };
    }
};

在这种情况下,MatrixUtility 实际上是必要的。

  1. 尽管如此,您还需要 MatrixUtility::identity&lt;T&gt;,因为有时需要单态:
template<typename T>
void foo(Matrix<T>);

auto a = MatrixUtility::identity(3, 3); // unexpected, a has type of Helper.
auto b = MatrixUtility::identity<int>(3, 3); // ok.
foo(MatrixUtility::identity(3, 3)); // ill-formed, T is not deducible.
foo(MatrixUtility::identity<int>(3, 3)); // well-formed.

最后,您选择的实现应该取决于您真正需要的。你需要一个多态,然后选择MatrixUtility::identity;您需要最简化,然后选择Matrix&lt;T&gt;::identity;而不是遵守固定的成语。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2015-05-14
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多