让我们看下这段程序:
很简单的一个重载;如我所愿,程序正常运行结果如下:
void func(int)
void func(T) [with T = Test]
现在,取消最后一行的注释,再次编译。。。
出现了如下编译错误:
test0.cc: In function ‘void func(T) [with T = short int]’:
test0.cc:28: instantiated from here
test0.cc:12: error: ‘short int’ is not a class, struct, or union type
一定很疑惑为什么编译器不会将short提升为int来选择第一个普通函数重载?
毕竟从函数签名来看,编译器不认为第一个函数是最合适的~
下面我们来尝试解决这个问题。
1.尝试给第二个函数的签名添加足够的信息。
第二个函数需要T内嵌有type类型,因此,修改签名,
给它添加一个参数类型
typename T::type且带默认值。
- template
- void func(T t, typename T::type = typename T::type())
- {
- typedef typename T::type type;
-
- std::cout << __PRETTY_FUNCTION__ << std::endl;
- }
重新编译,通过,运行结果如下:
void func(int)
void func(T, typename T::type) [with T = Test]
void func(int)
如我们所愿,第三个以short为参数进行的调用,匹配了第一个函数。
由于SIFNAE原理,编译器尽量不会让匹配失败产生错误,它知道short没有内嵌type类型,所以它把第二个函数从重载决议候选集合中删除了,因此只能匹配第一个,且将short提升为int。
2.另一种尝试
上述做法修改了函数的签名,能够尽量不对现有函数做改动呢?
boost给了一种方法:enable_if,充分利用了SIFNAE原理。
顾名思义,在给定条件满足时,不会将函数从重载候选集中排除,否则~~
它的代码非常简单:
- template
- struct enable_if
- {
- typedef T type;
- };
-
- template
- struct enable_if
- {
- };
现在我们开始修改第二个函数:
- template
- typename enable_if::value , void>::type func(T )
- {
- typedef typename T::type type;
-
- std::cout << __PRETTY_FUNCTION__ << std::endl;
- }
has_type的含义是:T是否有内嵌类型type,如果有,value为true;它的实现先不管。
这里的意思就是:如果T没有内嵌类型type,那么value为false,这样enable_if匹配了空模板,没有内嵌的type,由于SFINAE,该函数将不会被选择。
否则,如果T有内嵌类型type,那么value为true,enable_if将匹配基模板,拥有内嵌类型,这里为void,也即是该函数的返回类型。该函数将会被选择。
运行结果如下:
void func(int)
typename enable_if::value, void>::type func(T) [with T = Test]
void func(int)
最后贴一下has_type的实现,自己写的,估计有不对的地方,先放着后面看。