C++中"using"关键字背后的逻辑是什么?
What is the logic behind the "using" keyword in 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
在 C++11 中,用于type alias
的using
关键字与typedef
相同。
7.1.3.2
类型定义名称也可以通过别名声明引入。这 using 关键字后面的标识符成为 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; // 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 Standard
、Design 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 <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 模板"和 引入涉及"using"和"="对的新语法,以帮助避免 混淆:我们在这里没有定义任何类型,我们引入了一个 类型ID抽象的同义词(即别名)(即类型 表达式)涉及模板参数。如果模板参数 在类型表达式的可推导上下文中使用,然后每当 模板别名用于形成模板 ID,即 可以推导出相应的模板参数 - 更多关于此将 跟随。无论如何,现在可以编写泛型函数 在可推导的上下文中对
Vec<T>
进行操作,语法为 也得到了改进。例如,我们可以将foo重写为:template <typename T> void foo (Vec<T>&);
我们在此强调,提议的主要原因之一 模板别名是这样参数推导和调用
foo(p)
会成功的。
后续论文 n1489 解释了为什么using
而不是使用typedef
:
有人建议(重新)使用关键字 typedef — 如 论文 [4] — 引入模板别名:
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;
该表示法的优点是使用已知 引入类型别名。但是,它还显示几个 其中使用关键字的混淆已知 在别名的上下文中引入类型名称的别名 不是指定类型,而是指定模板;
Vec
不是 的别名 类型,并且不应用于类型定义名称。Vec
的名字是一个 家族名称std::vector< [bullet] , MyAllocator< [bullet] > >
– 其中项目符号是类型名称的占位符。因此,我们 不要建议使用"typedef"语法。另一方面,这句话template<class T> using Vec = std::vector<T, MyAllocator<T> >;
可以阅读/解释为:从现在开始,我将使用
Vec<T>
作为std::vector<T, MyAllocator<T> >
的同义词 .有了这个读数, 别名的新语法似乎合乎逻辑。
我认为这里进行了重要的区别,别名es 而不是类型s。同一文档中的另一句话:
别名声明是声明,而不是定义。别名- 声明将名称作为别名引入声明性区域 对于声明右侧指定的类型。这 此提案的核心涉及类型名称别名,但 符号显然可以概括以提供替代拼写 命名空间别名或重载函数的命名集(请参阅 ✁2.3 进一步讨论)。[我的注意:该部分讨论了该语法的外观以及它不是提案一部分的原因。可以注意到,语法生产别名声明在 typedef 的任何地方都是可以接受的 声明或命名空间别名定义是可以接受的。
总结,对于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);
命名一组重载。
// 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);
typedef和using之间的另一个区别: 你可以这样做:
using vector3d_t = double[3];
vector3d_t v = {1,2,3};
v[1] = 4;
使用typedef是不可能的:
typedef double[3] vector3d_t; // Compilation error
- "std::unique_XXX"命名约定背后的基本原理是什么?
- std::set<Key,Compare,Allocator>::find() 函数使用"<"运算符而不是"=="运算符背后的直觉是什么?
- while(sline >> n >> c && c== ',')背后的逻辑是什么?
- 有人能解释一下这些说法背后的逻辑是什么吗
- 在C++中为零大小的分配返回唯一地址背后的基本原理是什么?
- libc++ 的 std::basic_string 的 16 字节对齐模式背后的原因是什么?
- 不允许功能模板的部分专业化背后的理由是什么?
- 在查找子集中元素和元素数量之间的二进制比较背后的逻辑是什么?
- 不同向量启动作为类成员与方法中不同的矢量启动背后的原因是什么?
- typeid 运算符忽略 cv 限定符背后的理由是什么?
- 对于类型是类模板专业化的参数,ADL背后的理由是什么
- 模板类型背后的意义是什么?
- 以下程序背后的逻辑是什么
- 此代码中 * 1233 >> 12 计算十进制数字背后的数学原理是什么
- 当编译器看到 std::vector<Typo> 和 std::vector<struct 拼写错误时发出的诊断之间的差异背后的理由是什么>
- std::optional背后的基本原理是什么?
- 类实例和指针背后的Delphi设计原则是什么
- int64_t背后的魔力是什么
- C++中"using"关键字背后的逻辑是什么?
- "inline function need to be DEFINED in all tranlation units"背后的理由是什么?