“使用”的背后的逻辑是什么, C ++中的关键字? [英] What is the logic behind the "using" keyword in C++?

查看:66
本文介绍了“使用”的背后的逻辑是什么, C ++中的关键字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What is the logic behind the "using" keyword in C++?

它用于不同的情况,我试图找到
有一个共同点,有一个原因
为什么使用使用关键字这样。

It is used in different situations and I am trying to find if all those have something in common and there is a reason why the "using" keyword is used as such.

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


推荐答案

++ 11,使用关键字时,类型别名 typedef

In C++11, the using keyword when used for type alias is identical to typedef.

7.1.3.2


也可以通过别名声明引入。 using关键字之后的
标识符成为typedef名称,并且标识符后面的
可选属性 - 说明符seq在该typedef名称之后为
。它具有相同的语义,就像它是由typedef说明符引入的
。特别是,它没有定义
a新类型,它不会出现在类型id中。

A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type and it shall not appear in the type-id.

Bjarne Stroustrup提供一个实际示例:

Bjarne Stroustrup provides a practical example:

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,使用关键字可以将成员函数带入范围。在C ++ 11中,现在可以为构造函数(另一个Bjarne Stroustrup示例)执行此操作:

Pre-C++11, the using keyword can bring member functions into scope. In C++11, you can now do this for constructors (another Bjarne Stroustrup example):

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提供了不引入新关键字或新语法的原因。该标准希望尽可能避免破坏旧代码。这就是为什么在提案文档中你会看到对标准的影响设计决策旧代码。在某些情况下,一个建议似乎是一个很好的主意,但可能没有牵强,因为它太难实施,太混乱,或者会与旧的代码冲突。


Ben Voight provides a pretty good reason behind the rationale of not introducing a new keyword or new syntax. The standard wants to avoid breaking old code as much as possible. This is why in proposal documents you will see sections like Impact on the Standard, Design decisions, and how they might affect older code. There are situations when a proposal seems like a really good idea but might not have traction because it would be too difficult to implement, too confusing, or would contradict old code.

这是2003年的旧文件 n1449 。理由似乎与模板相关。警告:由于从PDF复制,可能会出现拼写错误。

Here is an old paper from 2003 n1449. The rationale seems to be related to templates. Warning: there may be typos due to copying over from PDF.


首先让我们考虑一个玩具示例:

First let’s consider a toy example:

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而不明确指定模板
参数。

The fundamental problem with this idiom, and the main motivating fact for this proposal, is that the idiom causes the template parameters to appear in non-deducible context. That is, it will not be possible to call the function foo below without explicitly specifying template arguments.

template <typename T> void foo (Vec<T>::type&);

所以,语法有些丑陋。我们宁愿避免嵌套 :: type
我们更喜欢如下:

So, the syntax is somewhat ugly. We would rather avoid the nested ::type We’d prefer something like the following:

template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage

注意,我们特别避免使用typedef template使用和=来帮助避免
的混淆:我们没有在这里定义任何类型,我们为一个类型的抽象引入一个
同义词(即别名) -id(即键入
expression)涉及模板参数。如果模板参数
用于类型表达式中的可推导的上下文中,则每当
模板别名用于形成模板id时,可以推断
对应的模板参数的值 - 更多的关于这将
跟随。在任何情况下,现在可以写出在可推导的上下文中对 Vec 进行操作的通用函数
,并且语法是
改进为好。例如我们可以重写foo为:

Note that we specifically avoid the term "typedef template" and intr oduce the new syntax involving the pair "using" and "=" to help avoid confusion: we are not defining any types here, we are introducing a synonym (i.e. alias) for an abstraction of a type-id (i.e. type expression) involving template parameters. If the template parameters are used in deducible contexts in the type expression then whenever the template alias is used to form a template-id, the values of the corresponding template parameters can be deduced – more on this will follow. In any case, it is now possible to write generic functions which operate on Vec<T> in deducible context, and the syntax is improved as well. For example we could rewrite foo as:

template <typename T> void foo (Vec<T>&);

我们这里强调,提出
模板别名的主要原因之一是,扣除和对 foo(p)
的调用将成功。

We underscore here that one of the primary reasons for proposing template aliases was so that argument deduction and the call to foo(p) will succeed.



< hr />

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


The follow-up paper n1489 explains why using instead of using typedef:


已经建议(重新)使用关键字typedef - 如
文档[4]中所做的 - 引入模板别名:

It has been suggested to (re)use the keyword typedef — as done in the paper [4] — to introduce template aliases:

template<class T> 
    typedef std::vector<T, MyAllocator<T> > Vec;

该符号的优点是使用已知的
引入一个类型别名。然而,它还显示了几个
disavantages,其中使用已知为
的关键字的混淆在别名的上下文中引入类型名称的别名
不指定类型,但是模板; Vec 不是
类型的别名,不应用于typedef名称。 Vec 的名称是家庭的
名称 std :: vector< [bullet],MyAllocator< [bullet]> >
- 其中项目符号是类型名称的占位符。因此,我们
不提出typedef语法。另一方面,句子

That notation has the advantage of using a keyword already known to introduce a type alias. However, it also displays several disavantages among which the confusion of using a keyword known to introduce an alias for a type-name in a context where the alias does not designate a type, but a template; Vec is not an alias for a type, and should not be taken for a typedef-name. The name Vec is a name for the family std::vector< [bullet] , MyAllocator< [bullet] > > – where the bullet is a placeholder for a type-name. Consequently we do not propose the "typedef" syntax. On the other hand the sentence

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

可以读取/解释为:从现在开始,我将使用 Vec< T> 作为
同义词 std :: vector< T,MyAllocator< T& > 。有了这个阅读,
新语法的混叠看起来是合理的。

can be read/interpreted as: from now on, I’ll be using Vec<T> as a synonym for std::vector<T, MyAllocator<T> >. With that reading, the new syntax for aliasing seems reasonably logical.

我认为这里有重要的区别, em>别名 es而不是类型。来自同一文档的另一个引用:

I think the important distinction is made here, aliases instead of types. Another quote from the same document:


别名声明是声明,而不是定义。 alias-
声明在声明区域中引入名称,作为声明右侧指定的类型的别名
。这个提议的
核心与类型名称别名有关,但是
表示法显然可以被概括为提供替换拼写
命名空间别名或重载函数的命名集合(见✁
2.3供进一步讨论)。 [我的注释:该部分讨论什么语法可以看起来和为什么它不是提案的一部分。]可以注意到语法生产别名声明是可以接受的任何地方typedef
声明或命名空间 - 别名定义是可以接受的。

An alias-declaration is a declaration, and not a definition. An alias- declaration introduces a name into a declarative region as an alias for the type designated by the right-hand-side of the declaration. The core of this proposal concerns itself with type name aliases, but the notation can obviously be generalized to provide alternate spellings of namespace-aliasing or naming set of overloaded functions (see ✁ 2.3 for further discussion). [My note: That section discusses what that syntax can look like and reasons why it isn't part of the proposal.] It may be noted that the grammar production alias-declaration is acceptable anywhere a typedef declaration or a namespace-alias-definition is acceptable.

摘要,对于


  • 模板别名(或模板typedef,前者是首选的)

  • 命名空间别名(即命名空间PO = boost :: program_options 使用PO = ...

  • 文档说 typedef声明可以被视为非模板别名声明的特殊情况。

  • 将范围(例如 namespace std )纳入全域范围范围),成员函数,继承构造函数

  • template aliases (or template typedefs, the former is preferred namewise)
  • namespace aliases (i.e., namespace PO = boost::program_options and using PO = ... equivalent)
  • the document says A typedef declaration can be viewed as a special case of non-template alias-declaration. It's an aesthetic change, and is considered identical in this case.
  • bringing something into scope (for example, namespace std into the global scope), member functions, inheriting constructors

不能用于:

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

这篇关于“使用”的背后的逻辑是什么, C ++中的关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆