อาร์กิวเมนต์เริ่มต้นของเทมเพลต


151

หากฉันได้รับอนุญาตให้ทำสิ่งต่อไปนี้:

template <typename T = int>
class Foo{
};

ทำไมฉันไม่ได้รับอนุญาตให้ทำสิ่งต่อไปนี้ในหลัก

Foo me;

แต่ฉันต้องระบุสิ่งต่อไปนี้:

Foo<int> me;

C ++ 11 นำเสนอข้อโต้แย้งแม่แบบเริ่มต้นและตอนนี้พวกเขากำลังเข้าใจความเข้าใจของฉันอย่างสมบูรณ์

คำตอบ:


188

คุณต้องทำ:

Foo<> me;

อาร์กิวเมนต์เทมเพลตต้องมีอยู่ แต่คุณสามารถปล่อยว่างไว้

คิดว่ามันเหมือนฟังก์ชั่นที่fooมีอาร์กิวเมนต์เริ่มต้นเดียว การแสดงออกfooจะไม่เรียกมันว่า แต่foo()จะ ไวยากรณ์ของอาร์กิวเมนต์ต้องยังคงอยู่ที่นั่น ซึ่งสอดคล้องกับสิ่งนั้น


4
@Pubby ฉันคิดว่ามันจะสร้างความยุ่งยากที่ไม่จำเป็นบางอย่างหากFoo อาจเป็นตัวระบุเทมเพลตหรืออาจเป็นอินสแตนซ์ที่ชัดเจนขึ้นอยู่กับว่ามีอาร์กิวเมนต์เริ่มต้นหรือไม่ ทำให้ไวยากรณ์อินสแตนซ์ที่ชัดเจนดีขึ้น คิดว่ามันเหมือนฟังก์ชั่นที่fooมีพารามิเตอร์เริ่มต้นเดียว คุณไม่สามารถเรียกมันชอบคุณเรียกมันว่าด้วยfoo foo()มันสมเหตุสมผลที่จะทำให้สิ่งนี้สอดคล้องกัน
Joseph Mansfield

2
@sftrabbit แต่คุณไม่สามารถเรียกใช้ฟังก์ชันที่ไม่มีอาร์กิวเมนต์เช่นfooกัน คุณสามารถตั้งชื่อชั้นเรียนกับการขัดแย้งใดเป็นFooอย่างไร
Seth Carnegie

4
@aschepler ด้วยฟังก์ชั่นข้อโต้แย้งแม่แบบสามารถอนุมานได้จากฟังก์ชั่นการโต้แย้ง ด้วยคลาสคุณไม่สามารถตัดสินใจได้ว่าคุณหมายถึงคลาสเทมเพลตที่มีอาร์กิวเมนต์เริ่มต้นหรือคลาสที่ไม่ใช่เทมเพลต
Olaf Dietsche

21
@OlafDietsche แต่คุณไม่สามารถมีคลาสเทมเพลตและคลาสที่ไม่ใช่เทมเพลตที่มีชื่อเดียวกันดังนั้นคอมไพเลอร์ควรตัดสินใจได้โดยดูที่ชื่อ
Seth Carnegie

7
@Pubby คณะกรรมการมาตรฐานถามตัวเองเหมือนกันฉันเดา ตอนนี้ด้วย C ++ 17 สิ่ง<>นี้ไม่จำเป็นอีกต่อไป ตรวจสอบคำตอบของฉันสำหรับรายละเอียดเพิ่มเติม
เปาโล M

53

ด้วย C ++ 17 คุณสามารถทำได้แน่นอน

คุณลักษณะนี้เรียกว่าแม่แบบเรียนอาร์กิวเมนต์หักและเพิ่มความยืดหยุ่นมากขึ้นกับวิธีที่คุณสามารถประกาศตัวแปรของประเภทเทมเพลต

ดังนั้น,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

คือตอนนี้ทางกฎหมายรหัส c ++


5
แปลก. เพิ่งลองในโครงการ C ++ 17 ของฉันและมันใช้งานไม่ได้: "เทมเพลตตัวยึดประเภท 'const MyType' ต้องตามด้วย declarator-id แบบง่าย" ฉันใช้ GCC 7.3.0
Silicomancer

1
@Silicomancer เป็นการยากที่จะพูดโดยไม่เห็นรหัสและบรรทัดคำสั่งของคุณ ... บางทีคุณอาจติดต่อกับพอยน์เตอร์ที่นี่ใช่ไหม
เปาโลเอ็ม

1
เสียงดังกราวไม่ยอมรับหรือไม่ coliru.stacked-crooked.com/a/c5d3c0f90ed263c2
Borgleader

1
@Borgleader เห็นได้ชัดว่า Coliru ใช้ clang 5.0 ตัดสินโดยสิ่งนี้มันควรสนับสนุนการหักล้างอาร์กิวเมนต์เทมเพลต C ++ 17 แต่รหัสไม่ชัดเจน หากคุณลองตัวอย่างเดียวกันในwandboxโดยใช้เสียงดังกราว 7.0 มันทำงานได้อย่างไม่มีที่ติ
เปาโล M

2
@PaoloM โอ้ยอดเยี่ยมดีใจที่ทราบว่าเป็นเพียงแค่รุ่นคอมไพเลอร์ ขอบคุณที่ตรวจสอบสิ่งนี้
Borgleader

19

คุณไม่ได้รับอนุญาตให้ทำเช่นนั้น แต่คุณสามารถทำได้

typedef Foo<> Fooo;

แล้วทำ

Fooo me;

มีความแตกต่างในเรื่องนี้กับประเภทเริ่มต้นและ: typedef Foo<float> Fooo;, โดยไม่ต้องพิมพ์เริ่มต้น?
qrikko

5
วิธี C ++ 11-ish จะบอกว่าusing Fooo = Foo<>;
เอเดรียน

18

คุณสามารถใช้สิ่งต่อไปนี้:

Foo<> me;

และintเป็นอาร์กิวเมนต์แม่แบบของคุณ วงเล็บเหลี่ยมเป็นสิ่งจำเป็นและไม่สามารถมองข้ามได้


ทำให้รู้สึกและขอบคุณ แต่ตามที่ระบุไว้ด้านล่างเหตุใดตัวระบุประเภทจึงมีอยู่
user633658

@ user633658: คุณหมายถึง "type specifier" หรือไม่ ฉันไม่แน่ใจว่าฉันเข้าใจ
Andy Prowl

อย่างไรก็ตามเกี่ยวกับเหตุผลที่อยู่เบื้องหลังความต้องการวงเล็บเหลี่ยมที่ว่างเปล่าฉันสามารถคาดเดาได้เท่านั้นและพวกเขาทั้งหมดเกี่ยวกับการขจัดความคลุมเครือที่เป็นไปได้ด้วยการใช้ชื่อเทมเพลตเพียงอย่างเดียว แต่ฉันต้องยอมรับว่าฉันไม่ทราบแน่ชัด เหตุผล
Andy Prowl

ฉันสงสัยอย่างยิ่งว่าความต้องการสำหรับ <> คือการเปิดใช้งานตัวแยกวิเคราะห์ของคอมไพเลอร์เพื่อตรวจสอบว่าคุณกำลังอ้างถึงคลาส templated ที่เรียกว่า foo แทนที่จะเป็นอย่างอื่นที่เรียกว่า foo
Mac
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.