Trong C ++ 11, using
từ khóa khi được sử dụng type alias
là giống hệt với typedef
.
7.1.3.2
Tên typedef cũng có thể được giới thiệu bằng một khai báo bí danh. Mã định danh theo sau từ khóa đang sử dụng trở thành tên typedef và thuộc tính-specifier-seq tùy chọn theo sau định danh xác định với tên typedef đó. Nó có cùng ngữ nghĩa như thể được giới thiệu bởi công cụ xác định typedef. Cụ thể, nó không định nghĩa một loại mới và nó sẽ không xuất hiện trong id loại.
Bjarne Stroustrup cung cấp một ví dụ thực tế:
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
Pre-C ++ 11, using
từ khóa có thể đưa các chức năng thành viên vào phạm vi. Trong C ++ 11, bây giờ bạn có thể làm điều này cho các nhà xây dựng (một ví dụ khác về 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 cung cấp một lý do khá chính đáng đằng sau lý do không giới thiệu từ khóa mới hoặc cú pháp mới. Các tiêu chuẩn muốn tránh phá vỡ mã cũ càng nhiều càng tốt. Đây là lý do tại sao trong các văn bản đề nghị, bạn sẽ thấy phần thích Impact on the Standard
, Design decisions
và làm thế nào họ có thể ảnh hưởng đến mã cũ. Có những tình huống khi một đề xuất có vẻ như là một ý tưởng thực sự tốt nhưng có thể không có lực kéo bởi vì nó quá khó để thực hiện, quá khó hiểu hoặc sẽ mâu thuẫn với mã cũ.
Đây là một bài báo cũ từ 2003 n1449 . Sự hợp lý dường như có liên quan đến các mẫu. Cảnh báo: có thể có lỗi chính tả do sao chép từ PDF.
Trước tiên hãy xem xét một ví dụ về đồ chơi:
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
Vấn đề cơ bản với thành ngữ này và thực tế thúc đẩy chính cho đề xuất này là thành ngữ này làm cho các tham số mẫu xuất hiện trong ngữ cảnh không thể khấu trừ. Đó là, sẽ không thể gọi hàm foo bên dưới mà không chỉ định rõ ràng các đối số khuôn mẫu.
template <typename T> void foo (Vec<T>::type&);
Vì vậy, cú pháp có phần xấu xí. Chúng tôi muốn tránh lồng nhau ::type
Chúng tôi muốn một cái gì đó như sau:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Lưu ý rằng chúng tôi đặc biệt tránh thuật ngữ khuôn mẫu typedef trực tuyến, và sử dụng cú pháp mới liên quan đến cặp sử dụng bằng cách sử dụng và sử dụng để tránh nhầm lẫn: chúng tôi không định nghĩa bất kỳ loại nào ở đây, chúng tôi đang giới thiệu một từ đồng nghĩa một sự trừu tượng hóa của một loại id (tức là biểu thức kiểu) liên quan đến các tham số mẫu. Nếu các tham số mẫu được sử dụng trong các ngữ cảnh có thể khấu trừ trong biểu thức kiểu thì bất cứ khi nào bí danh mẫu được sử dụng để tạo id mẫu, các giá trị của các tham số mẫu tương ứng có thể được suy ra - nhiều hơn về điều này sẽ theo sau. Trong mọi trường hợp, giờ đây có thể viết các hàm chung hoạt động Vec<T>
trong ngữ cảnh có thể khấu trừ và cú pháp cũng được cải thiện. Ví dụ, chúng ta có thể viết lại foo như:
template <typename T> void foo (Vec<T>&);
Chúng tôi nhấn mạnh ở đây rằng một trong những lý do chính để đề xuất bí danh mẫu là để suy luận đối số và lời kêu gọi foo(p)
sẽ thành công.
Bài viết tiếp theo n1361 giải thích lý do tại sao using
thay vì sử dụng typedef
:
Nó đã được đề xuất (tái) sử dụng từ khóa typedef - như được thực hiện trong bài báo [4] - để giới thiệu các bí danh mẫu:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Ký hiệu đó có lợi thế là sử dụng một từ khóa đã biết để giới thiệu một bí danh loại. Tuy nhiên, nó cũng hiển thị một số nhược điểm trong đó có sự nhầm lẫn khi sử dụng từ khóa được biết để giới thiệu bí danh cho tên loại trong ngữ cảnh mà bí danh không chỉ định một loại, mà là một mẫu; Vec
không phải là bí danh cho một loại và không nên lấy tên typedef. Tên Vec
này là một tên cho gia đình std::vector< [bullet] , MyAllocator< [bullet] > >
- trong đó viên đạn là một giữ chỗ cho một loại tên. Do đó, chúng tôi không đề xuất cú pháp typedef Lần. Mặt khác câu
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
có thể được đọc / giải thích như sau: từ bây giờ, tôi sẽ sử dụng Vec<T>
làm từ đồng nghĩa cho std::vector<T, MyAllocator<T> >
. Với cách đọc đó, cú pháp mới cho bí danh có vẻ hợp lý hợp lý.
Tôi nghĩ rằng sự khác biệt quan trọng được thực hiện ở đây, bí danh thay vì loại s. Một trích dẫn khác từ cùng một tài liệu:
Một khai báo bí danh là một tuyên bố, và không phải là một định nghĩa. Một khai báo bí danh giới thiệu một tên vào vùng khai báo dưới dạng bí danh cho loại được chỉ định bởi phía bên phải của khai báo. Cốt lõi của đề xuất này liên quan đến các bí danh tên loại, nhưng ký hiệu rõ ràng có thể được khái quát hóa để cung cấp các cách viết thay thế của bí danh không gian tên hoặc đặt tên các hàm quá tải (xem ✁ 2.3 để thảo luận thêm). [ Lưu ý của tôi: Phần đó thảo luận về cú pháp đó có thể trông như thế nào và lý do tại sao nó không phải là một phần của đề xuất. ] Có thể lưu ý rằng khai báo bí danh sản xuất ngữ pháp được chấp nhận ở bất cứ nơi nào một tuyên bố typedef hoặc một định nghĩa bí danh không gian tên được chấp nhận.
Tóm tắt, cho vai trò của using
:
- bí danh mẫu (hoặc typedefs mẫu, tên cũ được ưu tiên đặt tên)
- bí danh không gian tên (nghĩa là,
namespace PO = boost::program_options
vàusing PO = ...
tương đương)
- tài liệu nói
A typedef declaration can be viewed as a special case of non-template alias-declaration
. Đó là một thay đổi thẩm mỹ, và được coi là giống hệt nhau trong trường hợp này.
- đưa một cái gì đó vào phạm vi (ví dụ,
namespace std
vào phạm vi toàn cầu), các hàm thành viên, kế thừa các hàm tạo
Nó không thể được sử dụng cho:
int i;
using r = i; // compile-error
Thay vào đó hãy làm:
using r = decltype(i);
Đặt tên cho một bộ quá tả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);