“使用”的逻辑是什么?关键字在c++ ?

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
173148 次浏览

在c++ 11中,用于type aliasusing关键字与typedef相同。

7.1.3.2

typef -name也可以通过alias-declaration来引入。的 using关键字后面的标识符变成了typedef-name,而 可选的属性说明符-seq跟在标识符后面 到那个typef -name。它有相同的语义,就好像它是 由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; // not valid in C++11
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 StandardDesign 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 参数。< / p >
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(即类型)抽象的同义词(即别名) 表达式)涉及模板参数。如果模板参数 在类型表达式中的可演绎上下文中使用,然后何时 模板别名用于形成模板id,参数的值 相应的模板参数可以被推导出来-更多关于这个将 跟进。在任何情况下,现在都可以编写泛型函数 在可演绎上下文中操作Vec<T>,语法是 也有所改善。例如,我们可以将foo重写为:

template <typename T> void foo (Vec<T>&);
我们在这里强调求婚的主要原因之一 模板别名是这样的参数演绎和调用foo(p) 会成功。< / p >

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

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

template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
该表示法的优点是使用已知的关键字 引入类型别名。然而,它也显示了几个 缺点,其中使用一个关键字的混乱已知 在由别名构成的上下文中为类型名称引入别名 不是指定类型,而是指定模板;Vec不是类的别名 类型,并且不应该被当作typedef-name。名称Vec是一个 命名为家庭std::vector< [bullet] , MyAllocator< [bullet] > > -其中项目符号是类型名称的占位符。因此我们 不要提出“typedef”语法。另一方面句子

.
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;

可以读/解释为:从现在开始,我将使用Vec<T>作为a std::vector<T, MyAllocator<T> >的同义词。有了这样的阅读, 别名的新语法似乎是合理的逻辑

我认为这里有重要的区别,别名es而不是__abc1。另一段话摘自同一份文件:

alias-declaration是一个声明,而不是定义。一个别名。 声明将名称作为别名引入声明性区域 对于声明右边指定的类型。的 这个建议的核心是关注类型名别名,但是 符号显然可以泛化,以提供替代拼写 重载函数的命名空间别名或命名集(参见✁) 2.3,供进一步讨论)。[注:这一节讨论了该语法可以是什么样子,以及为什么它不是提案的一部分。]可能会注意到,语法生成别名声明在任何有类型定义的地方都是可接受的 声明或名称空间-别名-定义是可以接受的

总结,对于using的角色:

  • 模板别名(或模板类型defs,首选前者)
  • 命名空间别名(即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

而不是做的事:

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);

类型定义使用的另一个区别:你可以这样做:

    using vector3d_t = double[3];
vector3d_t v = {1,2,3};
v[1] = 4;

使用typedef是不可能的:

    typedef double[3] vector3d_t; // Compilation error