ใน C ++ 11 using
คำหลักเมื่อนำมาใช้สำหรับการที่จะเหมือนกันtype alias
typedef
7.1.3.2
นอกจากนี้คุณยังสามารถใช้ชื่อ typedef ได้โดยการประกาศนามแฝง ตัวระบุต่อจากคีย์เวิร์ดที่ใช้จะกลายเป็น typedef-name และแอ็ตทริบิวต์ - specifier-seq ที่เป็นทางเลือกตามหลังตัวระบุจะผนวกเข้ากับ typedef-name นั้น มันมีความหมายเหมือนกับว่ามันถูกนำมาใช้โดยตัวระบุ typedef โดยเฉพาะอย่างยิ่งมันไม่ได้กำหนดประเภทใหม่และจะไม่ปรากฏใน type-id
Bjarne Stroustrup ให้ตัวอย่างที่ใช้ได้จริง:
typedef void (*PFD)(double);
using PF = void (*)(double);
using P = [](double)->void;
using P = auto(double)->void
Pre-C ++ 11 using
คีย์เวิร์ดสามารถนำฟังก์ชันสมาชิกเข้าสู่ขอบเขต ใน C ++ 11 ตอนนี้คุณสามารถทำสิ่งนี้สำหรับตัวสร้างได้แล้ว (ตัวอย่าง Bjarne Stroustrup อื่น):
class Derived : public Base {
public:
using Base::f;
void f(char);
void f(int);
using Base::Base;
Derived(char);
Derived(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;
ปัญหาพื้นฐานของสำนวนนี้และข้อเท็จจริงที่เป็นแรงจูงใจหลักสำหรับข้อเสนอนี้คือสำนวนทำให้พารามิเตอร์เทมเพลตปรากฏในบริบทที่ไม่สามารถอนุมานได้ นั่นคือจะไม่สามารถเรียกใช้ฟังก์ชัน foo ด้านล่างโดยไม่ระบุอาร์กิวเมนต์เทมเพลตอย่างชัดเจน
template <typename T> void foo (Vec<T>::type&);
ดังนั้นไวยากรณ์จึงค่อนข้างน่าเกลียด เราค่อนข้างจะหลีกเลี่ยงสิ่งที่ซ้อนกัน::type
เราต้องการสิ่งต่อไปนี้:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >;
Vec<int> p;
โปรดทราบว่าเราหลีกเลี่ยงคำว่า "เทมเพลต typedef" โดยเฉพาะและแนะนำไวยากรณ์ใหม่ที่เกี่ยวข้องกับคู่ "ใช้" และ "=" เพื่อช่วยหลีกเลี่ยงความสับสน: เราไม่ได้กำหนดประเภทใด ๆ ที่นี่เราขอแนะนำคำพ้องความหมาย (เช่นนามแฝง) สำหรับ นามธรรมของ type-id (เช่นนิพจน์ประเภท) ที่เกี่ยวข้องกับพารามิเตอร์เทมเพลต หากใช้พารามิเตอร์เทมเพลตในบริบทที่อนุมานไม่ได้ในนิพจน์ชนิดเมื่อใดก็ตามที่ใช้นามแฝงเทมเพลตเพื่อสร้าง template-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] > >
- โดยที่สัญลักษณ์แสดงหัวข้อย่อยเป็นตัวยึดสำหรับ type-name ดังนั้นเราจึงไม่เสนอไวยากรณ์ "typedef" ในทางกลับกันประโยค
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
สามารถอ่าน / ตีความว่าเป็น: จากนี้ไปผมจะใช้เป็นคำพ้องสำหรับVec<T>
std::vector<T, MyAllocator<T> >
ด้วยการอ่านดังกล่าวไวยากรณ์ใหม่สำหรับนามแฝงดูเหมือนมีเหตุผล
ฉันคิดว่าความแตกต่างที่สำคัญเกิดขึ้นที่นี่นามแฝง es แทนที่จะเป็นประเภท s คำพูดอื่นจากเอกสารเดียวกัน:
การประกาศนามแฝงเป็นการประกาศไม่ใช่คำจำกัดความ นามแฝง - การประกาศแนะนำชื่อในพื้นที่ประกาศเป็นนามแฝงสำหรับประเภทที่กำหนดโดยด้านขวามือของการประกาศ แกนหลักของข้อเสนอนี้เกี่ยวข้องกับนามแฝงของชื่อประเภท แต่เห็นได้ชัดว่าสัญกรณ์สามารถนำไปใช้ในการสะกดแบบอื่นของเนมสเปซ - นามแฝงหรือชุดการตั้งชื่อของฟังก์ชันที่โอเวอร์โหลด (ดู✁ 2.3 สำหรับการสนทนาเพิ่มเติม) [ หมายเหตุของฉัน: ส่วนนั้นจะกล่าวถึงลักษณะของไวยากรณ์และเหตุผลว่าทำไมจึงไม่เป็นส่วนหนึ่งของข้อเสนอ ] อาจสังเกตได้ว่าการประกาศนามแฝงการผลิตไวยากรณ์เป็นที่ยอมรับได้ทุกที่ที่ยอมรับการประกาศ typedef หรือการกำหนดเนมสเปซนามแฝง
สรุปสำหรับบทบาทของusing
:
- ชื่อแทนเทมเพลต (หรือ template 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;
แทนที่จะทำ:
using r = decltype(i);
การตั้งชื่อชุดโอเวอร์โหลด
using std::cos;
using std::cos(double);
using test = std::cos(double);