在C ++ 11中,using
关键字用于时type alias
与相同typedef
。
7.1.3.2
typedef名称也可以通过别名声明来引入。using关键字后面的标识符变为typedef名称,而标识符后面的可选attribute-specifier-seq属于该typedef名称。它具有与typedef说明符引入的语义相同的语义。特别是,它没有定义新的类型,也不应出现在type-id中。
Bjarne Stroustrup提供了一个实际示例:
typedef void (*PFD)(double); // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP
在C ++ 11之前的版本中,using
关键字可以将成员函数带入范围。在C ++ 11中,您现在可以对构造函数执行此操作(另一个Bjarne Stroustrup示例):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
在不引入新关键字或新语法的基本原理之后,Ben Voight提供了一个很好的理由。该标准希望尽可能避免破坏旧代码。这就是为什么在建议文件,你会看到喜欢的部分Impact on the Standard
,Design decisions
以及它们如何影响老年人的代码。在某些情况下,提案似乎是一个不错的主意,但可能没有吸引力,因为提案难以实施,过于混乱或与旧代码矛盾。
这是2003 n1449的一篇旧论文。基本原理似乎与模板有关。警告:由于从PDF复制而可能出现错别字。
首先让我们考虑一个玩具示例:
template <typename T>
class MyAlloc {/*...*/};
template <typename T, class A>
class MyVector {/*...*/};
template <typename T>
struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage
这种习语的根本问题以及该建议的主要动机是,该习语导致模板参数出现在不可推论的上下文中。也就是说,如果不显式指定模板参数,则无法调用下面的函数foo。
template <typename T> void foo (Vec<T>::type&);
因此,语法有点难看。我们宁愿避免嵌套,::type
我们更喜欢以下内容:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
请注意,我们特别避免使用“ typedef template”一词,并引入涉及“ using”和“ =”对的新语法,以帮助避免混淆:我们此处未定义任何类型,我们引入了同义词(即别名)涉及模板参数的类型标识(即类型表达式)的抽象。如果在类型表达式中的可推导上下文中使用模板参数,则每当使用模板别名来形成模板ID时,都可以推导相应模板参数的值-接下来将进行更多介绍。在任何情况下,现在都可以编写可Vec<T>
在可推断上下文中运行的通用函数,并且语法也得到了改进。例如,我们可以将foo重写为:
template <typename T> void foo (Vec<T>&);
我们在此强调,提出模板别名的主要原因之一是要使参数推导和to调用foo(p)
成功。
后续论文n1489解释了为什么using
不使用typedef
:
建议(重新)使用关键字typedef(如论文[4]所述)来引入模板别名:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
该符号的优点是使用已知的关键字来引入类型别名。但是,它也显示了一些缺点,其中在别名不是指定类型而是模板的情况下,使用已知的关键字为类型名称引入别名的困惑。Vec
不是类型的别名,并且不应将其用作typedef名称。名称Vec
是家庭的名称std::vector< [bullet] , MyAllocator< [bullet] > >
–项目符号是类型名称的占位符。因此,我们不建议使用“ typedef”语法。另一方面句子
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
可以理解为:从现在开始,我将Vec<T>
用作的同义词std::vector<T, MyAllocator<T> >
。通过阅读,别名的新语法似乎是合理的。
我认为重要区别在于别名 es而不是类型 s。同一文档中的另一句话:
别名声明是声明,而不是定义。别名声明将名称引入声明性区域,作为声明右侧指定的类型的别名。该建议的核心涉及类型名称别名,但显然可以将其概括为提供名称空间别名或重载函数的命名集的替代拼写(有关更多讨论,请参见第2.3节)。[ 我的注释:该部分讨论了语法的外观以及为什么它不属于提案的原因。可以注意到,语法生成别名声明在任何可接受的typedef声明或namespace-alias-definition都是可以接受的。
总结,作用using
:
- 模板别名(或模板typedefs,以名称为准)
- 命名空间的别名(即,
namespace PO = boost::program_options
和using PO = ...
当量)
- 文件说
A typedef declaration can be viewed as a special case of non-template alias-declaration
。这是一种美学上的变化,在这种情况下被认为是相同的。
- 将某些东西带入范围(例如,
namespace std
全局范围),成员函数,继承构造函数
它不能用于:
int i;
using r = i; // compile-error
而是:
using r = decltype(i);
命名一组重载。
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);