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,也可以完成相同的功能。