从C++17开始,using声明语句被扩展了,声明多个标识符时可以在一行进行声明,用逗号分隔即可。如下面的代码所示:
namespaceA{voidg(){cout"g()"endl;};voidf(){cout"f()"endl;};}namespaceX{usingA::f,A::g;}
在C++17之前,使用多个using声明时要分别进行声明。
1使用变长的using声明
在实际编程时,通过使用可变的using声明可以实现泛型代码从可变数量的所有基类中派生同一种运算。这种方法的典型应用场景就是可以创建一个统一的lambda操作符重载。如下面的代码,通过可变类模板和一个自动推断向导实现了一个实现重载统一定义的lambda表达式。
#includeiostreamusingnamespacestd;templatetypename...Tsstructoverload:Ts...{usingTs::operator()...;};templatetypename...Tsoverload(Ts...)-overloadTs...;autooperCalc=overload{[](std::strings){coutsendl;;},[](autov){v*=2;}};intmain(){stringstr="hello";operCalc(str);autosum=1.5;operCalc(sum);coutsumendl;return0;}
在支持C++17的编译器中,上面的代码可以正常运行结果,针对上面的代码解释如下:
templatetypename...Tsstructoverload:Ts...{usingTs::operator()...;};
上面这个实际是定义一个可变的类模板,templatetypename...Ts是类模板的可变参数包。structoverload:Ts...这里Ts实际上是overload基类继承的所有参数类型。usingTs::operator()...就是一个可变的using声明。
overload(Ts...)-overloadTs...实际上是一个自动推导器,用来告诉编译器根据传入的参数类型推导出类模板的参数类型。
在上面的示例中,如果传入的是string类型参数,会匹配到[](std::strings){coutsendl;;},如果传入整型或者auto的数值型参数则会匹配到[](autov){v*=2;}这个lambda表达式。
除了这个应用场景外,这个技术的另一个典型应用是std::variant访问器。这个访问器将在后续的文章中进行介绍。
2使用变长using声明继承构造函数在C++17中,可以声明一个可变参数的类模板。这个类模板可以继承一个基类。基类可以代表任意参数类型。如下面的代码:
templatetypenameTclassBase{public:Base(){};Base(T_v):value(_v){coutvalueendl;};private:Tvalue{};};templatetypename...TypesclassSubClass:privateBaseTypes...{public:usingBaseTypes::Base...;};intmain(){usingSubClassInst=SubClassint,double,std::string,bool;SubClassInststrTmp(std::string("hello,world"));SubClassInstiTmp();SubClassInstdTmp(50.4);return0;}
在上面代码中,派生类中使用了基类构造函数的using声明,就是派生类具备继承了每一种传入类型的声明。如在本例中,使用using声明了4种类型。
usingSubClassInst=SubClassint,double,std::string,bool;
声明后就可以使用SubClassInst定义已经声明了的数据类型变量。上面的代码运行结果为:
3总结
如果想要深入了解using声明请参考下面两个链接:
参考链接: