У C ++ 11 using
ключове слово при використанні для type alias
нього ідентичне typedef
.
7.1.3.2
Ім'я typedef також може бути введено декларацією псевдоніму. Ідентифікатор, що відповідає ключовому слову, що використовується, стає іменем typedef, а необов'язковий атрибут-specier-seq, що слідує за ідентифікатором, відноситься до цього імені typedef. Він має таку саму семантику, як якщо б вона була введена специфікатором typedef. Зокрема, він не визначає новий тип і не повинен відображатися в ідентифікаторі типу.
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 є досить вагомою причиною обґрунтування невведення нового ключового слова чи нового синтаксису. Стандарт хоче максимально уникнути порушення старого коду. Ось чому в реченні документів ви побачите розділи подобається 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 template" і вкладаємо в нього новий синтаксис, що включає пари "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. Ім'я 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 або простір імен-alias-definition є прийнятною.
Підсумок, на роль 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);