2.13 局部和匿名类型作模板实参
类别:部分人
在C++98中,标准对模板实参的类型还有一些限制。具体地讲,局部的类型和匿名的类型在C++98中都不能做模板类的实参。比如,如代码清单2-30所示的代码在C++98中很多都无法编译通过。
代码清单2-30
template<typename T>class X{};
template<typename T>void TempFun(T t){};
struct A{}a;
struct{int i;}b;//b是匿名类型变量
typedef struct{int i;}B;//B是匿名类型
void Fun()
{
struct C{}c;//C是局部类型
X<A>x1;//C++98通过,C++11通过
X<B>x2;//C++98错误,C++11通过
X<C>x3;//C++98错误,C++11通过
TempFun(a);//C++98通过,C++11通过
TempFun(b);//C++98错误,C++11通过
TempFun(c);//C++98错误,C++11通过
}
//编译选项:g++ -std=c++11 2-13-1.cpp
在代码清单2-30中,我们定义了一个模板类X和一个模板函数TempFun,然后分别用普通的全局结构体、匿名的全局结构体,以及局部的结构体作为参数传给模板。可以看到,使用了局部的结构体C及变量c,以及匿名的结构体B及变量b的模板类和模板函数,在C++98标准下都无法通过编译。而除了匿名的结构体之外,匿名的联合体以及枚举类型,在C++98标准下也都是无法做模板的实参的。如今看来这都是不必要的限制。所以在C++11中标准允许了以上类型做模板参数的做法,故而用支持C++11标准的编译器编译以上代码,代码清单2-30所示代码可以通过编译。
不过值得指出的是,虽然匿名类型可以被模板参数所接受了,但并不意味着以下写法可以被接受,如代码清单2-31所示。
代码清单2-31
template<typename T>struct MyTemplate{};
int main(){
MyTemplate<struct{int a;}>t;//无法编译通过,匿名类型的声明不能在模板实参位置
return 0;
}
//编译选项:g++ -std=c++11 2-13-2.cpp
在代码清单2-31中,我们把匿名的结构体直接声明在了模板实参的位置。这种做法非常直观,但却不符合C/C++的语法。在C/C++中,即使是匿名类型的声明,也需要独立的表达式语句。要使用匿名结构体作为模板参数,则可如同代码清单2-30一样对匿名结构体作别名。此外在第4章我们还会看到使用C++11独有的类型推导decltype,也可以完成相同的功能。