C++中typename和template的其他用处

C++中,typename和template的最基础用法是在模板声明中,这个太常见了,所以不再赘述,我们要讨论的是typename和template的另一用处,本文的参考地址:Where and why do I have to put the “template” and “typename” keywords?

typename

在C++中,有些情况下,编译器需要显式地知道如何对待一个表达式,而这些情况有一点是共同的:他们都至少涉及到了一个模板参数。如果一个表达式在解析的时候,可能会有歧义,那么我们就称呼为“dependent names”,中文也许可以叫它依赖名称。

先看一段可能引起歧义的代码

template<class T> void f_tmpl () { T::foo * x; /* <-- (A) */ }

T::foo *x想表达什么意思?可能有两种完全不同的意思,请看以下两行代码:

struct X { typedef int       foo;       }; /* (C) --> */ f_tmpl<X> ();
struct Y { static  int const foo = 123; }; /* (D) --> */ f_tmpl<Y> ();
  • 如果用X实例化函数模板,则T::foo *x的意思是声明一个int指针。

  • 如果用Y实例化函数模板,则T::foo *x表示两个变量相乘。

现在问题来了,作为写下f_tmpl的程序员,我们心中肯定是有一个预期的,我们预期的T::foo到底是一个类型还是一个变量?默认情况下,C++假定通过作用域运算符访问的名字不是类型,所以这里当作两个变量相乘,从而编译报错:x,找不到标识符。这就和我们的预期不符合了,我想要T::foo当一个类型啊,结果编译器给我整成变量了,咋办?我该如何告诉编译器它不是变量?

有办法,typename登场!C++标准允许开发者在处理dependent names的时候,即解析可能有歧义的时候,手动添加typename标识符,来显式地告诉编译器,请把它当作类型来解析。至于什么是dependent names,开篇已经介绍过了。关于T::foo这种格式,还有一个特定的称呼,叫做“qualified names ”,中文也许可以称呼为限定名称,即从一个目标中限定名称,T::foo、f->value、f.value,这种都可以叫做qualified names。

我们似乎可以总结出一个规律,只有涉及到模板参数而且是qualified names的时候,才会出现歧义。仅仅是模板参数的话,那要么是类型,要么是变量,都不会有歧义,如下代码。

template<int i, typename T>
void function()
{
	i* 10;//无歧义,变量i 乘以 10
	T* t; //无歧义,类型T的指针
	float f;
	{
		T::value * f; //歧义!T::value是变量还是类型?
	}
}

所以凡是涉及到模板参数且是qualified names的时候,在编译器认为既可能是变量也可能是类型的时候(即有歧义的时候),如果我们希望是类型,就添加typename标识。

C++20之前,如果T::value这种出现的地方要求value是类型,但程序员没有添加typename标识,C++会认为不对,编译报错,如下代码

//================before C++20==============
template<typename T>
struct TemplateStruct
{
			 T::value * t;  //compile error!
	typename T::value * t2; //ok!
};

以上代码中, T::value *t不会被当作一个乘法,这个时候对于编译器来说,它不认为有歧义,编译器:这个区域你给我老老实实声明变量,我也只认变量声明!如果不添加typename标识,就会出现编译错误。

C++20对于typename的限制放宽了很多。如果T::value出现的地方,要求value必须是类型,那么程序员可以不用添加typename(添加也没有问题,这是为了兼容旧版本的代码)

//C++20
template<typename T>
struct TemplateStruct
{
			 T::value * t;  //ok! 不需要再添加typename标识了
	typename T::value * t2; //ok! 添加也不会有问题
};

template

当遇见typename T::value<>这种格式,且value是模板的时候,如果想显示地告诉编译器,把value当模板处理,则应当使用T::template value这种格式。如果不这样做,会怎么样?

boost::function< int() > f;

以上代码,既可以理解成一个函数模板,也可以理解成boost中有个function变量,先做一个小于 0,再做一个大于f。如果写成

boost::template function< int() > f;

则boost::function就是一个模板了。

一个良好的习惯是,任何时候使用typename T::value<>这种代码,如果value是个模板,则应该写成typename T::template value<>。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值