C++中"using"关键字背后的逻辑是什么?

use*_*311 111 c++ c++11

C++中"using"关键字背后的逻辑是什么?

它用于不同的情况,我试图找出是否所有这些都有共同点,并且有一个理由为什么使用"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
Run Code Online (Sandbox Code Playgroud)

小智 93

在C++ 11中,using用于的关键字type aliastypedef.

7.1.3.2

也可以通过别名声明引入typedef-name.using关键字后面的标识符变为typedef-name,并且该标识符后面的可选attribute-specifier-seq属于该typedef-name.它具有与typedef说明符引入的语义相同的语义.特别是,它没有定义新类型,它不应出现在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
Run Code Online (Sandbox Code Playgroud)

在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) 
    // ...
}; 
Run Code Online (Sandbox Code Playgroud)

Ben Voight提供了一个很好的理由,它背后的理由是不引入新关键字或新语法.该标准希望尽可能避免破坏旧代码.这就是为什么在建议文件,你会看到类似的部分Impact on the Standard,Design decisions以及它们如何影响老年人的代码.在某些情况下,提案似乎是一个非常好的主意,但可能没有牵引力,因为它实施起来太困难,太混乱,或者与旧代码相矛盾.


这是2003年至1449年的一篇旧论文.理由似乎与模板有关.警告:由于从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
Run Code Online (Sandbox Code Playgroud)

这个习语的根本问题,以及这个提议的主要动机是,这个习惯用法使模板参数出现在不可导出的上下文中.也就是说,如果没有明确指定模板参数,就不可能在下面调用函数foo.

template <typename T> void foo (Vec<T>::type&);
Run Code Online (Sandbox Code Playgroud)

所以,语法有点难看.我们宁愿避免嵌套::type 我们更喜欢以下内容:

template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Run Code Online (Sandbox Code Playgroud)

请注意,我们特别避免使用术语"typedef模板",并引入涉及"using"和"="对的新语法,以帮助避免混淆:我们没有在此定义任何类型,我们引入了同义词(即别名)涉及模板参数的type-id(即类型表达式)的抽象.如果模板参数在类型表达式中的可推导上下文中使用,那么每当使用模板别名来形成模板ID时,可以推导出相应模板参数的值 - 接下来将对此进行更多介绍.在任何情况下,现在可以编写Vec<T>在可推导上下文中操作的泛型函数,并且语法也得到改进.例如,我们可以将foo重写为:

template <typename T> void foo (Vec<T>&);
Run Code Online (Sandbox Code Playgroud)

我们在此强调,提出模板别名的主要原因之一是参数推断和调用foo(p) 将成功.


后续文件n1489解释了为什么using而不是使用typedef:

有人建议(重新)使用关键字typedef - 如文[4]所述 - 引入模板别名:

template<class T> 
    typedef std::vector<T, MyAllocator<T> > Vec;
Run Code Online (Sandbox Code Playgroud)

该符号具有使用已知的关键字引入类型别名的优点.然而,它还显示了一些不利之处,其中混淆使用已知的关键字在别名未指定类型但模板的上下文中为类型名称引入别名; Vec不是类型的别名,不应该用于typedef-name.该名称Vec是该系列的名称std::vector< [bullet] , MyAllocator< [bullet] > > - 其中项目符号是类型名称的占位符.因此,我们不建议使用"typedef"语法.另一方面这句话

template<class T>
    using Vec = std::vector<T, MyAllocator<T> >;
Run Code Online (Sandbox Code Playgroud)

可以被读/解释为:从现在开始,我将Vec<T>用作同义词std::vector<T, MyAllocator<T> >.通过该读取,用于别名的新语法似乎合理逻辑.

我认为这里有一个重要的区别,别名而不是类型 s.同一文件的另一个引用:

别名声明是声明,而不是定义.别名声明将声明区域中的名称引入为声明右侧指定的类型的别名.该提议的核心与类型名称别名有关,但该符号显然可以概括为提供命名空间别名的替代拼写或命名的重载函数集(有关进一步的讨论,请参阅✁2.3).[ 我的注释:该部分讨论了该语法的外观以及它不属于提案的原因.]可以注意到,语法生成别名声明在typedef声明或namespace-alias-definition可接受的任何地方都是可接受的.

总结,对于以下角色using:

  • 模板别名(或模板typedef,前者是名字的首选)
  • 命名空间的别名(即,namespace PO = boost::program_optionsusing 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
Run Code Online (Sandbox Code Playgroud)

相反:

using r = decltype(i);
Run Code Online (Sandbox Code Playgroud)

命名一组重载.

// 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);
Run Code Online (Sandbox Code Playgroud)

  • @ user3111311你有什么其他的关键词?"汽车"?"寄存器"? (2认同)
  • “使用P = [](double)-&gt; void;”是AFAIK,无效的C ++ 11。但是,这是:使用P = auto(double)-&gt; void;生成函数类型(例如P *是函数指针)。 (2认同)
  • 他的名字是Bjarne Stroustrup;)(注意Stroustrup的第二个r) (2认同)
  • 不幸的是,“register”开始了一个变量声明,所以这已经有意义了。声明一个名为 Y、类型为 X 的寄存器变量。 (2认同)