首页 > 解决方案 > 正确的模板习语(直觉)

问题描述

我试图以更深层次的概念理解 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<T>::Identity方式将是一个类的单位矩阵 value_type = T

TL;博士

重申一下,我相信上面的模板会生成一Matrix<T>::Identity具有各自“类型”静态成员的类。这是与一些其他直观语义的比较,Matrix::Identity<T>()后者将是T所有矩阵的类型标识。哪个是对的?

标签: c++classtemplatesmember

解决方案


Matrix<T>::identity没有任何其他条件,和之间没有什么不同Matrix::identity<T>。它看起来像someFunction<T>。所以没有任何成语。

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

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

  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<T>,因为有时需要单态:
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<T>::identity;而不是遵守固定的成语。


推荐阅读