C++17中Mat<Mat>编译报错:默认模板参数为何未自动生效?
Mat<Mat>编译失败,而Mat<Mat<>>可行? 首先得理清C++17引入的**类模板实参推导(CTAD, Class Template Argument Deduction)**的适用场景——这是理解问题的核心。
1. 为什么Mat mat1能正常工作?
当你直接声明Mat mat1时,编译器触发了CTAD:因为你没有提供模板参数,编译器会尝试用类模板的默认参数(这里T=double)推导具体类型,最终等价于Mat<double> mat1;。这完全符合C++17的CTAD规则。
2. 为什么Mat<Mat>会报错?
问题出在模板参数的位置:当你写Mat<Mat>时,外层Mat的模板参数需要一个具体的类型,但Mat本身只是一个类模板的名称,不是一个具体类型。
CTAD的设计是为了简化对象的初始化,而不是为了在类型上下文(比如模板参数列表)中自动把类模板名转换成具体类型。编译器不会在模板参数位置自动为内层的Mat触发CTAD——它只会把Mat当作未指定参数的类模板,而不是一个可用的类型,所以会报错“Use of class template 'Mat' requires template arguments”。
3. 为什么Mat<Mat<>>是正确的?
Mat<>的写法是显式触发CTAD的一种方式:当你写Mat<>时,编译器会为这个类模板名推导默认参数,得到具体类型Mat<double>。此时外层的Mat<Mat<>>就等价于Mat<Mat<double>>——内层是一个具体类型,外层的模板参数也就合法了。
简单来说:
Mat→ 类模板名称(不是类型)Mat<>→ 通过CTAD推导得到的具体类型(Mat<double>)Mat<Mat<>>→ 外层Mat的模板参数是具体类型Mat<double>,合法。
总结
C++17的CTAD只在直接初始化对象的场景下自动生效,在类型上下文(比如作为其他模板的参数)中,你必须显式地将类模板转换为具体类型——要么指定完整参数,要么用<> 触发CTAD推导默认参数。
内容的提问来源于stack exchange,提问作者thewoz

