在阅读Boost.ASIO的时候看到了下面这种写法:
template <typename CompletionToken, typename Signature = void>
class async_result
{
public:
//...
typedef CompletionToken completion_handler_type;
async_result<completion_handler_type> legacy_result_;
};
template <typename Handler>
class async_result<Handler>
{
//...
};
先开始没注意到下面这个偏特化版本,导致我始终不明白上面legacy_result_的成员声明那种写法,这看起来不是死循环了吗。但注意到偏特化模板类后又注意到一个问题,对于这种默认模板参数与偏特化都能匹配的时候,是实例化哪种版本的模板类。(虽然从上面的写法中已经可以推理出答案了。。)
还是动手测试下:
先是在一个头文件中定义了2个模板类,模仿上面的情况。
template <class T, typename U = void>
class test {
public:
test() {
std::cout << "默认模板参数版本" << std::endl;
}
};
template <class T>
class test<T> {
public:
test() {
std::cout << "偏特化版本" << std::endl;
}
};
然后在main函数中创建一个test类型的局部变量:
int main() {
test<int> t;
}
输出
偏特化版本
看得出来优先匹配偏特化的版本。
接下来再做另一个测试,这次改为传入2个模板参数,不过2个模板类的定义也要稍微改下:
template <class T, typename U = void>
class test {
public:
test() {
std::cout << "默认模板参数版本" << std::endl;
}
};
template <class T>
class test<T, int> { // 注意这里多了一个模板参数
public:
test() {
std::cout << "偏特化版本" << std::endl;
}
};
这里只改了偏特化版本,使其具有2个模板参数。
此时main函数中再创建一个test变量:
int main() {
test<int, int> t;
test<int> t2;
}
输出
偏特化版本
默认模板参数版本
看得出来都是优先匹配偏特化版本的模板类。
下面再做另一个例子,再修改下默认模板参数:
template <class T, typename U = int> // 这里改了
class test {
public:
test() {
std::cout << "默认模板参数版本" << std::endl;
}
};
template <class T>
class test<T, int> {
public:
test() {
std::cout << "偏特化版本" << std::endl;
}
};
int main() {
test<int, int> t1;
test<int> t2;
}
输出
偏特化版本
偏特化版本
这个例子的结果很有意思,test<int>竟然是实例化的偏特化模板,刚看到的时候愣住了,不过后来也想通了。应该是编译器看到test<int>先匹配到了默认模板参数版本template <class T, typename U = int>,得到了模板参数<int, int>,然而这时候并没有直接去实例化test类,它再找这个模板参数的最佳匹配,结果找到了偏特化版本并去实例化它。
以上结果来自我猜测,若有错误望知情人士指正。
总结来说:
模板实例化顺序应该还是优先匹配偏特化版本的。
博客探讨了C++模板在遇到偏特化版本和默认模板参数都能匹配时的实例化顺序。通过示例代码展示了在不同情况下,编译器如何选择优先匹配偏特化模板,以及一个特殊例子中,编译器如何在找到默认模板参数后进一步寻找最佳匹配的过程。结论是模板实例化通常优先考虑偏特化版本。
5818

被折叠的 条评论
为什么被折叠?



