Подтвердить что ты не робот

Какова логика ключевого слова "using" в С++?

Какова логика ключевого слова "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
4b9b3361

Ответ 1

В С++ 11 ключевое слово using при использовании для type alias идентично typedef.

7.1.3.2

Имя typedef также может быть введено с помощью объявления alias. идентификатор после ключевого слова using становится typedef-name и необязательный атрибут-спецификатор-seq, следующий за идентификатором. к этому typedef-name. Он имеет ту же семантику, как если бы это было введенный спецификатором typedef. В частности, он не определяет новый тип и он не будет отображаться в идентификаторе типа.

Bjarne Stroustrup дает практический пример:

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-С++ 11, ключевое слово using может вводить функции-члены в область видимости. В С++ 11 вы можете сделать это для конструкторов (другой пример Bjarne Stroustrup):

class Derived : public Base { 
public: 
    using Base::f;    // lift Base f into Derived 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 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&);

Итак, синтаксис несколько уродлив. Мы предпочли бы избежать вложенных ::typeWed предпочитает что-то вроде следующего:

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

Обратите внимание, что мы специально избегаем термина "шаблон typedef" и intr oduce новый синтаксис с участием пары "using" и "=", чтобы избежать путаница: мы не определяем какие-либо типы здесь, мы вводим синоним (т.е. псевдоним) для абстракции идентификатора типа (т.е. типа выражение) с использованием параметров шаблона. Если параметры шаблона используются в выводимых контекстах в выражении типа, тогда псевдоним шаблона используется для формирования идентификатора шаблона, значения можно определить соответствующие параметры шаблона - подробнее об этом будет следовать. В любом случае теперь можно писать общие функции которые работают на 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 не является псевдонимом для тип и не следует принимать для typedef-name. Имя Vec является имя для семейства std::vector< [bullet] , MyAllocator< [bullet] > >- где пуля является заполнителем для имени типа. Следовательно, мы не предлагайте синтаксис typedef. С другой стороны, предложение

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

может быть прочитан/интерпретирован как: с этого момента Ill будет использовать Vec<T> как синоним для std::vector<T, MyAllocator<T> >. С этим чтением новый синтаксис для псевдонимов кажется достаточно логичным.

Я думаю, что здесь делается важное различие, алиасы вместо типов. Другая цитата из того же документа:

Алиасовая декларация - это декларация, а не определение. Алиас- декларация вводит имя в декларативный регион как псевдоним для типа, указанного в правой части декларации. Ядро этого предложения касается имен псевдонимов типов, но Очевидно, что обозначение может быть обобщено для обеспечения альтернативного написания пространства имен или смены имен перегруженных функций (см. ✁  2.3 для дальнейшего обсуждения). [ Мое примечание. В этом разделе обсуждается, как может выглядеть этот синтаксис и почему он не является частью предложения.] Можно отметить, что декларация о псевдонимах грамматики допустима везде, где typedef декларация или определение псевдонима пространства имен.

Сводка, для роли using:

  • псевдонимы шаблонов (или типовые typedefs, первый предпочтительнее).
  • псевдонимы пространства имен (т.е. 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);