模板偏特化和默认模板参数的匹配顺序

博客探讨了C++模板在遇到偏特化版本和默认模板参数都能匹配时的实例化顺序。通过示例代码展示了在不同情况下,编译器如何选择优先匹配偏特化模板,以及一个特殊例子中,编译器如何在找到默认模板参数后进一步寻找最佳匹配的过程。结论是模板实例化通常优先考虑偏特化版本。

在阅读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类,它再找这个模板参数的最佳匹配,结果找到了偏特化版本并去实例化它。

以上结果来自我猜测,若有错误望知情人士指正。

总结来说:
模板实例化顺序应该还是优先匹配偏特化版本的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值