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
答案 0 :(得分:77)
在C ++ 11中,用于using
的{{1}}关键字与type alias
相同。
7.1.3.2
也可以通过别名声明引入typedef-name。该 using关键字后面的标识符变为typedef-name和 标识符appertains后面的可选attribute-specifier-seq 到那个typedef-name。它具有与它相同的语义 由typedef说明符引入。特别是,它没有定义 一个新类型,它不应出现在type-id。
中
Bjarne Stroustrup提供了一个实际的例子:
typedef
Pre-C ++ 11,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
关键字可以将成员函数纳入范围。在C ++ 11中,您现在可以为构造函数执行此操作(另一个Bjarne Stroustrup示例):
using
Ben Voight提供了一个很好的理由,它背后的理由是不引入新关键字或新语法。该标准希望尽可能避免破坏旧代码。这就是为什么在提案文档中,您会看到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)
// ...
};
,Impact on the Standard
等部分,以及它们可能会如何影响旧代码。有些情况下,提案似乎是一个非常好的主意,但可能没有牵引力,因为它实施起来太困难,太混乱,或者与旧代码相矛盾。
这是2003年n1449的一篇旧论文。理由似乎与模板有关。警告:由于从PDF复制而可能存在拼写错误。
首先让我们考虑一个玩具示例:
Design decisions
这个成语的根本问题,以及主要的激励因素 对于这个提议,是成语导致模板参数 出现在不可导出的背景下。也就是说,它是不可能的 在不明确指定模板的情况下调用下面的函数foo 参数。
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
所以,语法有些难看。我们宁愿避免嵌套
template <typename T> void foo (Vec<T>::type&);
我们更喜欢以下内容:::type
请注意,我们特别避免使用术语“typedef template”和intr 引入涉及“using”和“=”对的新语法以帮助避免 困惑:我们在这里没有定义任何类型,我们正在介绍一个 用于抽象类型id的同义词(即别名)(即类型 表达式)涉及模板参数。如果是模板参数 在任何时候用于类型表达式的可推导上下文中 模板别名用于形成模板ID,值的 可以推导出相应的模板参数 - 更多关于这一点 跟随。无论如何,现在可以编写通用函数 它在可导入的上下文中以
template <typename T> using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below Vec<int> p; // sample usage
运行,语法是 也改善了。例如,我们可以将foo重写为:Vec<T>
我们在此强调提出的主要原因之一 模板别名是为了使参数推断和调用
template <typename T> void foo (Vec<T>&);
会成功的。
后续文件n1489解释了为什么foo(p)
而非使用using
:
有人建议(重新)使用关键字typedef - 就像在。中所做的那样 论文[4] - 介绍模板别名:
typedef
该符号具有使用已知关键字的优势 引入一个类型别名。但是,它也显示了几个 使用已知关键字的混淆的不利之处 在别名的上下文中引入类型名称的别名 不指定类型,而是指定模板;
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;
不是a的别名 type,不应该用于typedef-name。名称Vec
是一个 家庭的姓名Vec
- 项目符号是类型名称的占位符。因此我们 不建议使用“typedef”语法。另一方面句子std::vector< [bullet] , MyAllocator< [bullet] > >
可以被读取/解释为:从现在开始,我将使用
template<class T> using Vec = std::vector<T, MyAllocator<T> >;
作为Vec<T>
的同义词。随着那个阅读, 别名的新语法似乎合理逻辑。
我认为这里有一个重要的区别, alias es而不是 type 。同一文件的另一个引用:
别名声明是声明,而不是定义。别名 - 声明将名称引入声明性区域作为别名 对于声明右侧指定的类型。该 该提案的核心与类型名称别名有关,但是 显然可以概括表示法以提供替代拼写 命名空间别名或命名的重载函数集(参见✁ 2.3进一步讨论)。 [我的注释:该部分讨论了该语法的外观以及它不属于提案的原因。]可以注意到,语法生成别名声明在任何地方都可以接受的typedef 声明或命名空间别名定义是可以接受的。
摘要,关于std::vector<T, MyAllocator<T> >
的作用:
using
和namespace PO = boost::program_options
等效)using 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);