问题描述
我正在尝试更深入地理解 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;DR
重申一下,我相信上面的模板会生成一个 set 类,其中包含各自“类型”的静态成员 Matrix<T>::Identity
。这与某些 Matrix::Identity<T>()
的其他直观语义相比,后者是所有矩阵的 T
类型的标识。哪个是正确的?
解决方法
没有任何其他条件,Matrix<T>::identity
和 Matrix::identity<T>
没有什么不同。它只是看起来像 someFunction<T>
。所以没有任何成语。
但另一方面,很多实际问题会让你选择更好的。
-
Matrix::identity<T>
是什么?如果Matrix<T>
表示元素类型为T
的矩阵类,那么Matrix
本身是什么?它是一个类模板,所以它不能有任何没有实例化的成员。在这种情况下,您应该定义一个单独的类(例如,名为MatrixUtility
),并使用MatrixUtility::identity<T>
。听起来很吵吧? -
但是,
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
实际上是必要的。
- 尽管如此,您还需要
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
;而不是遵守固定的习惯用法。