当前位置: 首页 > 知识库问答 >
问题:

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

百里文景
2023-03-14

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

共有1个答案

谢叶五
2023-03-14

在C++11中,用于类型别名using关键字与typedef相同。

7.1.3.2

也可以通过别名声明引入typedef-name。using关键字后面的标识符成为typedef-name,标识符后面的可选属性-specifier-seq属于该typedef-name。它具有与由typedef说明符引入的相同的语义。特别是,它不定义一个新的类型,它不应该出现在类型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为不引入新关键字或新语法提供了一个很好的理由。该标准希望尽可能避免破坏旧代码。这就是为什么在建议文档中,您会看到诸如对标准的影响设计决策等部分,以及它们可能如何影响较旧的代码。有些情况下,一个建议看起来是一个很好的想法,但可能没有吸引力,因为它太难实现,太混乱,或者与旧的代码相矛盾。

这是一篇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”和“=”这对的新语法,以帮助避免混淆:我们在这里不定义任何类型,而是引入了涉及模板参数的type-id(即类型表达式)抽象的同义词(即别名)。如果在类型表达式中的可推演上下文中使用模板参数,那么无论何时使用模板别名来形成模板ID,都可以推导出相应模板参数的值--后面会有更多关于这方面的内容。无论如何,现在可以在可推论的上下文中编写操作vec 的泛型函数,语法也得到了改进。例如,我们可以将foo改写为:

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

我们在这里强调,提出模板别名的一个主要原因是为了使参数推导和对foo(p)的调用能够成功。

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

有人建议(重新)使用关键字typedef(如论文[4]中所做的那样)来引入模板别名:

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

这种表示法的优点是使用已知的关键字来引入类型别名。然而,它也显示了几个不可取之处,其中包括在别名不指定类型而是指定模板的上下文中使用已知的关键字为类型名引入别名的混乱;vec不是类型的别名,不应用作typedef名称。名称vec是系列std::vector<[bullet],myallocator<[bullet]>的名称,其中bullet>是类型名的占位符。因此,我们不建议使用“typedef”语法。另一方面,这句话

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

可以读/解释为:从现在起,我将使用vec 作为std::vector > 的同义词。这样看来,别名的新语法似乎合乎逻辑。

我认为重要的区别就在这里,别名而不是类型。另一段引用自同一文件:

别名声明是声明,而不是定义。别名声明将一个名称作为声明右侧指定的类型的别名引入声明性区域。这个建议的核心是关于类型名称别名,但是这个符号显然可以推广到提供名称空间别名或重载函数命名集的替换拼写(进一步讨论请参见2.3)。[我的注意:这一节讨论了该语法的外观以及它不是建议一部分的原因。]可以注意到,在可以接受typedef声明或namespace-alias-definition的地方,语法生成alias-definition都是可以接受的。

关于使用的角色摘要:

  • 模板别名(或模板typedefs,在名称方面首选前者)
  • 命名空间别名(即命名空间PO=boost::program_options和使用PO=...等效的)
  • 文档说可以将typedef声明视为非模板alias-declaration的一种特殊情况。这是一个美学上的变化,在本例中被认为是相同的。
  • 将某些内容带入作用域(例如,将命名空间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);

 类似资料:
  • 我正试图从现实中解决一个问题 “偶数总和” 但是我不能这样做。下面是问题。 即使是总和也是两个玩家的游戏。玩家将获得N个正整数序列并轮流进行。在每个回合中,玩家选择一个非空切片(连续元素的子序列),使得该切片中的值之和是偶数,然后删除切片并连接序列的其余部分。第一个无法做出合法举动的玩家将输掉比赛。 如果你和你的对手玩这场游戏,你想知道你是否能赢,假设你和对手都玩得很好。你先走。 写一个函数:

  • 问题内容: 我碰到了Java行,并对它的输出感到困惑。您能否解释一下此代码背后的逻辑 输出: 问题答案: 好吧,它等效于: 真正地将原始内容显式转换为只是使其调用而不是。 我相信to 转换 实际上首先 要进行隐式加宽转换-就像这样: 这些帮助有用?

  • 问题内容: 众所周知,某些Python的数据结构使用 哈希表 存储诸如或的项目。因此,这些对象没有顺序。但似乎,对于某些数字序列,这是不正确的。 例如,请考虑以下示例: 但是,如果我们进行一些小的更改,则无法排序: 所以问题是:Python的哈希函数如何在整数序列上工作? 问题答案: 尽管SO的问题及其顺序有很多问题,但没有人解释哈希函数的算法。 因此,这里您所需要的就是知道python如何计算哈

  • 问题内容: Java是否具有在休眠状态下打开会话时可以使用的using语句? 在C#中,它类似于: 因此,对象超出范围并自动关闭。 问题答案: Java 7引入了自动资源块管理,该功能将该功能引入了Java平台。Java的早期版本没有任何相似之处。 例如,您可以使用通过以下方式实现的任何变量: 由流实现的Java 接口自动扩展,因此您可以像在C#块中使用流一样使用块中的流。这等效于C#的。 从5.

  • 我想创建一个二维游戏与瓷砖为基础的地图。我的主要问题是碰撞。如果有一棵树挡住了我的路,我怎么才能让我的精灵不穿过这棵树呢?