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++中“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中,using关键字用于类型别名时与typedef相同。
7.1.3.2
typef -name也可以通过别名声明引入。的 using关键字后面的标识符变成了typedef-name,而 可选的属性说明符-seq跟在标识符后面 到那个typef -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 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中复制,可能会出现错别字。
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 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&); 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 Note that we specifically avoid the term “typedef template” and introduce 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>&); 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.
后续论文n1489解释了为什么使用而不是使用typedef:
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; 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> >; 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.
我认为这里有重要的区别,别名而不是类型。另一段话摘自同一份文件:
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.
总结,对于使用的作用:
模板别名(或模板类型defs,首选前者) 命名空间别名(例如,命名空间PO = boost::program_options和使用PO =…当量) 文档中说,typedef声明可以被视为一种特殊的非模板别名声明。这是美学上的变化,在这种情况下被认为是相同的。 将某些内容引入作用域(例如,将名称空间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