ขอบเขตของการประกาศ "ใช้" ใน C ++ คืออะไร?


101

ฉันใช้การประกาศ 'ใช้' ใน C ++ เพื่อเพิ่ม std :: string และ std :: vector ไปยังเนมสเปซในเครื่อง (เพื่อบันทึกการพิมพ์ 'std ::' ที่ไม่จำเป็น)

using std::string;
using std::vector;

class Foo { /*...*/ };

ขอบเขตของคำประกาศนี้คืออะไร? หากฉันทำสิ่งนี้ในส่วนหัวจะฉีดคำประกาศ 'โดยใช้' เหล่านี้ลงในไฟล์ cpp ทุกไฟล์ที่มีส่วนหัวหรือไม่


18
ในกรณีที่ยังไม่ชัดเจนจากคำตอบอื่น ๆ ที่นี่: - อย่าวางusingคำประกาศ (หรือusingคำสั่ง) ไว้ที่ขอบเขตไฟล์ใน include file / header! นั่นจะสร้างความปวดหัวให้กับผู้ใช้ส่วนหัว
Michael Burr

ในความเป็นจริงไม่ใส่usingประกาศ (ก fortiori สั่ง ) ในส่วนหัวที่ทุกคน , แม้จะอยู่ใน namespace! ดูขอบเขตของการใช้การประกาศภายในเนมสเปซสำหรับปัญหานี้
Nils von Barth

@NilsvonBarth: มันง่ายไปหน่อย การใช้usingในคลาสและขอบเขตฟังก์ชันนั้นปลอดภัยสำหรับปัญหาที่กล่าวถึง
Sebastian Mach


คุณอาจจะสนใจที่จะอ่านเกี่ยวกับการค้นหา ADL c ++ คุณลักษณะ
Alexis Wilke

คำตอบ:


60

เมื่อคุณ # รวมไฟล์ส่วนหัวใน C ++ ไฟล์จะวางเนื้อหาทั้งหมดของไฟล์ส่วนหัวลงในจุดที่คุณรวมไว้ในไฟล์ต้นฉบับ ดังนั้นการรวมไฟล์ที่มีการusingประกาศจะมีผลเหมือนกันusingทุกประการในการวางการประกาศไว้ที่ด้านบนของแต่ละไฟล์ที่มีไฟล์ส่วนหัวนั้น


53
... ซึ่งโดยทั่วไปเป็นสิ่งที่ไม่ดี
Catskul

17
แต่ถ้าคุณใส่usingคำประกาศไว้namespaceในขอบเขตของเนมสเปซนั้นโดยทั่วไปก็ใช้ได้ (โดยมีข้อแม้ตามปกติเกี่ยวกับความต้องการและสไตล์เฉพาะของคุณ)
Zero

1
... แต่ถ้าคุณใช้ภายในเนมสเปซตรวจสอบให้แน่ใจว่าคุณไม่ได้ทำเพื่อพยายามหลีกเลี่ยงสิ่งที่ปกติเป็นความคิดที่ไม่ดีเช่นคุณไม่สามารถเข้ารหัสเมธอดคลาสที่ประกาศไว้นอกเนมสเปซ Y ภายในอีกอัน เนมสเปซ X เพื่อให้คุณสามารถใช้เนมสเปซ X ในเครื่องได้นั่นคือเหตุผลที่เราใช้ namespace :: resolvers ตั้งแต่แรก หากเป็นปัญหาใหญ่ในการพิมพ์ไม่ว่าจะเป็นมาโคร (ซึ่งอาจทำให้เกิดกลิ่นโค้ดได้ง่าย) หรือดีกว่านั้นให้แยกออกเป็น. cpp ซอร์สของตัวเองซึ่งคุณจะใช้เนมสเปซที่นั่นเท่านั้น
osirisgothra

1
แม้ว่าคำตอบนี้และคำตอบที่คล้ายกันจะเป็นคำแนะนำที่ดี แต่ก็ไม่ได้ตอบคำถาม
Emile Cormier

116

ไม่มีอะไรพิเศษเกี่ยวกับไฟล์ส่วนหัวที่จะทำให้การusingประกาศออกไป เป็นการแทนที่ข้อความอย่างง่ายก่อนที่การคอมไพล์จะเริ่มขึ้น

คุณสามารถ จำกัด การusingประกาศเป็นขอบเขต:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}

12
ฉันไม่เคยคิดเลยว่าจะสามารถใช้มันในฟังก์ชันได้!
Agostino

1
ฉันมีเนมสเปซจำนวนมากที่ใช้โดยไฟล์ประเภท "ผู้รวบรวมข้อมูล" หนึ่งไฟล์และการทดสอบหน่วย gmock นั้นน่าเบื่อเป็นพิเศษเพราะการทดสอบแต่ละครั้งใช้สิ่งต่างๆจากเนมสเปซที่เฉพาะเจาะจงและฉันคิดว่าฉันต้องมีคุณสมบัติแต่ละตัวแปร การใช้usingฟังก์ชันภายใน (หรือแม้แต่TESTมาโครที่ละเอียดที่สุด!) ทำให้ชีวิตของฉันดีขึ้นมาก
dwanderson

56

ขอบเขตของคำสั่งใช้ขึ้นอยู่กับตำแหน่งที่อยู่ในรหัส:

  • วางไว้ที่ด้านบนสุดของไฟล์จะมีขอบเขตตลอดทั้งไฟล์นั้น
  • หากเป็นไฟล์ส่วนหัวไฟล์จะมีขอบเขตในไฟล์ทั้งหมดที่มีส่วนหัวนั้น โดยทั่วไปนี่ไม่ใช่ " ความคิดที่ดี " เนื่องจากอาจมีผลข้างเคียงที่คาดไม่ถึง
  • มิฉะนั้นคำสั่งใช้จะมีขอบเขตภายในบล็อกที่มีตั้งแต่จุดที่เกิดขึ้นจนถึงจุดสิ้นสุดของบล็อก หากวางไว้ในเมธอดก็จะมีขอบเขตภายในเมธอดนั้น หากวางไว้ในนิยามคลาสก็จะมีขอบเขตภายในคลาสนั้น

6
ฉันคิดว่ามันเป็นไปไม่ได้ที่จะเพิ่มusingคำสั่งภายในขอบเขตชั้นเรียน ... ? ฉันมีคำถามเดียวกันกับ OP เพราะเหตุนี้เนื่องจากฉันต้องการหลีกเลี่ยงการพิมพ์std::ทั่วทุกที่ ฉันมีชั้นเรียนที่ใช้เวกเตอร์จำนวนมากพร้อมตัวชี้อัจฉริยะและstd::คำนำหน้าอักขระห้าตัวเพิ่มความยาวบรรทัดมากซึ่งฉันพบว่าอ่านแย่ลง ฉันจึงสงสัยว่าusingคำสั่งภายในเนมสเปซที่มีคลาสนั้นใช้ได้หรือไม่? (แม้ว่าภายในหัว.)
thomthom

5
แล้วถ้าวางไว้ในขอบเขตของ a namespace { ... }?
einpoklum

คุณจึงสามารถเขียน: {โดยใช้ namespace blabla; คลาส blah {}; } และการใช้นั้นจะใช้กับคลาสเท่านั้นหรือไม่
Dinaiz

8

ขอบเขตคือขอบเขตใดก็ตามที่มีการประกาศใช้

หากเป็นขอบเขตทั่วโลกก็จะอยู่ในขอบเขตทั่วโลก หากอยู่ในขอบเขตส่วนกลางของไฟล์ส่วนหัวไฟล์นั้นจะอยู่ในขอบเขตส่วนกลางของไฟล์ต้นฉบับทุกไฟล์ที่มีส่วนหัว

ดังนั้นคำแนะนำทั่วไปคือการหลีกเลี่ยงการใช้ declarations ในขอบเขตทั่วโลกของไฟล์ส่วนหัว


3
นั่นไม่แข็งแรงพอ แทนที่การหลีกเลี่ยงด้วย Don't
Martin York

1
หลีกเลี่ยง BUt แรงกว่าไม่ทำ "หลีกเลี่ยงการชนรถคันอื่น"
bobobobo

6

ในกรณีที่อ้างถึงคือไฟล์ ("หน่วยการแปล") ซึ่งหมายความว่าใช่ทุกไฟล์ที่มี

คุณยังสามารถใส่คำสั่งใช้ภายในคลาสซึ่งในกรณีนี้จะมีผลกับคลาสนั้น ๆ เท่านั้น

โดยทั่วไปหากคุณจำเป็นต้องระบุเนมสเปซในส่วนหัวมักจะเป็นการดีที่สุดที่จะระบุคุณสมบัติทั้งหมดที่จำเป็นเท่านั้น


โปรดสังเกตว่าการusingประกาศในชั้นเรียนจะไม่ทำงานในลักษณะเดียวกับภายนอกคลาส - เช่นคุณไม่สามารถใช้การประกาศในคลาสcoutแทนstd::coutได้
Zero

2

ถูกต้อง. ขอบเขตคือโมดูลที่ใช้การusingประกาศ หากไฟล์ส่วนหัวใด ๆ ที่โมดูลรวมไว้มีusingการประกาศขอบเขตของการประกาศเหล่านั้นจะเป็นโมดูลนั้นเช่นเดียวกับโมดูลอื่น ๆ ที่มีส่วนหัวเดียวกัน


1

มีความคิดเห็นบางส่วนที่ค่อนข้างไม่มีเงื่อนไขเมื่อพวกเขาพูดว่า "อย่า" นั่นเป็นเรื่องที่เข้มงวดเกินไป แต่คุณต้องเข้าใจเมื่อมันตกลง

การเขียนusing std::stringไม่เคยตกลง การเขียนusing ImplementationDetail::Fooในส่วนหัวของคุณเองเมื่อส่วนหัวนั้นประกาศ ImplementationDetail :: Foo ก็สามารถทำได้นอกจากนี้หากการประกาศใช้เกิดขึ้นในเนมสเปซของคุณ เช่น

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
จากนั้นผู้ใช้ส่วนหัวสามารถเขียนได้MyNS::Foo
Peter Remmers

using boost::posix_time::ptimeตัวอย่างที่ดีคือ แน่นอนว่าผู้ใช้สามารถเขียนได้MyNS::ptimeแต่นั่นไม่ใช่จุดจบของโลกและอาจถูกชดเชยด้วยความสะดวกในการมีฟังก์ชันเช่นMyFunction(ptime a, ptime b).
Zero

5
ทำไมเป็นusing std::stringไม่เคย ok? แม้แต่ในเนมสเปซของคุณเองเพื่อบันทึกstd::คำนำหน้าจำนวนมาก?
thomthom

@thomthom มันก็โอเคเมื่ออยู่ในขอบเขตเช่นเนมสเปซของคุณเอง
jcoffland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.