C ++中“using”关键字的逻辑是什么?
C ++中“using”关键字的逻辑是什么?
它用于不同的情况,我试图找出是否所有这些都有共同的东西,有一个原因,为什么使用“使用”的关键字。
using namespace std; // to import namespace in the current namespace using T = int; // type alias using SuperClass::X; // using super class methods in derived class
在C ++ 11中,用于type alias
的using
关键字与typedef
相同。
7.1.3.2
typedef-name也可以通过别名声明来引入。 using关键字后面的标识符变为typedef-name,标识符后面的可选attribute-specifier-seq属于该typedef-name。 它具有与由typedef说明符引入的相同的语义。 特别是它没有定义一个新的types,它不会出现在type-id中。
Bjarne Stroustrup提供了一个实际的例子:
typedef void (*PFD)(double); // C style using PF = void (*)(double); // using plus C-style type using P = [](double)->void; // using plus suffix return type, syntax error using P = auto(double)->void // Fixed thanks to DyP
Pre-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模板”这个术语,并引入涉及“using”和“=”的新语法以避免混淆:我们在这里没有定义任何types,我们引入了一个同义词涉及模板参数的typesid(即typesexpression式)的抽象。 如果模板参数被用在typesexpression式中的可引用的上下文中,那么无论何时使用模板别名来形成模板标识符,相应的模板参数的值都可以被推断出来。 在任何情况下,现在都可以在可
Vec<T>
上下文中编写在Vec<T>
上运行的generics函数,并且语法也得到了改进。 例如,我们可以将foo重写为:template <typename T> void foo (Vec<T>&);
我们在这里强调,提出模板别名的主要原因之一是,争论推理和对
foo(p)
的调用将会成功。
后续文件n1489解释了为什么使用typedef
而不是:
有人build议(重新)使用关键字typedef(如文章[4]所述)来引入模板别名:
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;
该符号具有使用已知引入types别名的关键字的优点。 然而,它也显示出一些缺点,其中在别名没有指定types的上下文中使用已知的为关键字名称引入别名的关键字的混淆,而是模板;
Vec
不是一个types的别名,不应该用于typedef-name。 名称Vec
是std::vector< [bullet] , MyAllocator< [bullet] > >
– 其中,bullet是types名称的占位符。 因此我们不提出“typedef”语法。 另一方面的句子template<class T> using Vec = std::vector<T, MyAllocator<T> >;
可以被读取/解释为:从现在开始,我将使用
Vec<T>
作为std::vector<T, MyAllocator<T> >
的同义词。 通过阅读,用于别名的新语法似乎合乎逻辑。
我认为重要的区别是在这里, 别名 es而不是type s。 来自同一文件的另一个引用:
别名声明是一个声明,而不是一个定义。 别名声明在声明区域中引入一个名称作为声明右侧指定types的别名。 这个提议的核心是关于types名称的别名,但是这个符号显然可以被推广到提供替代的命名空间别名拼写或命名的重载函数集合(见2.3节的进一步讨论)。 [ 我的笔记:这部分讨论了这个语法可能的样子,以及为什么它不是提案的一部分。 ]可以注意到,在typedef声明或名称空间别名定义可接受的地方,语法生成别名声明是可接受的。
总结,对于using
的angular色:
- 模板别名(或模板types定义,前者是首选的名称)
- 命名空间别名(即
namespace PO = boost::program_options
和using PO = ...
等价物) - 该文件说
A typedef declaration can be viewed as a special case of non-template alias-declaration
。 这是一种美学上的改变,在这种情况下被认为是相同的。 - 将某些东西带入范围(例如,
namespace std
进入全局范围),成员函数,inheritance构造函数
它不能用于:
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);