การใช้คำหลักแบบอินไลน์กับเทมเพลตมีความหมายหรือไม่?


119

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


แก้ไข: ฉันต้องการยอมรับทั้งสองคำตอบ แต่ไม่สามารถทำได้ เพื่อปิดปัญหาฉันยอมรับคำตอบของวลีเนื่องจากได้รับการโหวตมากที่สุดและเขาก็ถูกต้องอย่างเป็นทางการ แต่อย่างที่ฉันพูดถึงในความคิดเห็นฉันถือว่าคำตอบของPuppyและComponent 10เป็นคำตอบที่ถูกต้องเช่นกันจากมุมมองที่แตกต่างกัน .

ปัญหาอยู่ในความหมายของ C ++ ซึ่งไม่เข้มงวดในกรณีของinlineคีย์เวิร์ดและอินไลน์ วลีระบุว่า "เขียนอินไลน์ถ้าคุณหมายถึง" แต่ความหมายที่แท้จริงinlineยังไม่ชัดเจนเนื่องจากมีการพัฒนาจากความหมายดั้งเดิมไปเป็นคำสั่งที่ว่า "หยุดคอมไพเลอร์ที่ยุ่งเกี่ยวกับการละเมิด ODR" ตามที่Puppyกล่าว

คำตอบ:


96

มันไม่เกี่ยว และไม่ไม่ใช่ทุกเทมเพลตฟังก์ชันจะเป็นinlineค่าเริ่มต้น มาตรฐานนี้มีความชัดเจนแม้กระทั่งในExplicit specialization ([temp.expl.spec])

มีดังต่อไปนี้:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (นำมาจาก Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

รวบรวมสิ่งนี้ et voila:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

การไม่ระบุinlineเมื่อทำการสร้างอินสแตนซ์ที่ชัดเจนอาจทำให้เกิดปัญหาได้เช่นกัน

ดังนั้นโดยสรุป : สำหรับเทมเพลตฟังก์ชันที่ไม่เชี่ยวชาญโดยสิ้นเชิงเช่นเทมเพลตที่มีประเภทที่ไม่รู้จักอย่างน้อยหนึ่งประเภทคุณสามารถละเว้นinlineและไม่ได้รับข้อผิดพลาด แต่ก็ยังไม่เป็นinlineเช่นนั้น สำหรับความเชี่ยวชาญพิเศษทั้งหมด ได้แก่ ประเภทที่ใช้เฉพาะประเภทที่รู้จักคุณไม่สามารถละเว้นได้

หลักทั่วไปที่เสนอ : เขียนinlineว่าคุณหมายถึงหรือไม่และสอดคล้องกัน มันทำให้คุณคิดน้อยลงว่าจะทำหรือไม่เพียงเพราะคุณทำได้ (หลักทั่วไปนี้สอดคล้องกับเทมเพลต C ++ของ Vandevoorde / Josuttis : The Complete Guide )


2
อาจมีคนเขียนว่าจริง แต่นั่นไม่ได้หมายความถึงความไม่เป็นธรรมชาติแม้ว่ามันจะเป็นเช่นนั้นก็ตาม Vandevoorde และ Josuttis ยังระบุอย่างชัดเจนในเทมเพลต C ++: The Complete Guide
Sebastian Mach

43
ความเชี่ยวชาญเฉพาะด้านอย่างชัดเจนไม่ใช่เทมเพลต
ลูกสุนัข

2
@DeadMG: ฟังก์ชั่นปกตินั้นเป็นที่ต้องการมากกว่าความเชี่ยวชาญพิเศษทั้งหมดในการค้นหาดังนั้นหากพวกเขาไม่ใช่เทมเพลตหรือไม่ใช่เทมเพลตพวกเขาจะเป็นอย่างไร
Sebastian Mach

13
คำตอบนี้ไม่ถูกต้อง ความเชี่ยวชาญเฉพาะด้านอย่างชัดเจนของเทมเพลตคือฟังก์ชันไม่ใช่เทมเพลต ฟังก์ชั่นที่ไม่ได้กลายเป็นเพียงเพราะแม่แบบที่เป็นผู้เชี่ยวชาญจะมีเครื่องหมายinline inlineดังนั้นinlineในเทมเพลตจึงไม่เกี่ยวข้องโดยสิ้นเชิง ฟังก์ชั่นนั้นควรจะเป็นinlineหรือไม่ไม่มีส่วนเกี่ยวข้องใด ๆ จากการสร้างผ่านความเชี่ยวชาญพิเศษของเทมเพลต (และมีคำตอบที่ดีกว่าที่อยู่นี้เมื่อจะใช้inline) คำตอบของ @Puppy ด้านล่างถูกต้องอันนี้ไม่ใช่ การเพิ่มinlineเทมเพลตไม่เกี่ยวข้องและclang-tidyจะลบออกจริง
gnzlbg

6
นอกจากนี้ตัวอย่างยังแสดงปัญหา ODR สำหรับฟังก์ชันปกติ (ลักษณะการทำงานไม่มีส่วนเกี่ยวข้องกับเทมเพลต) จะพยายามแสดงให้เห็นว่า inlineจะไม่เป็นที่ไม่เกี่ยวข้องเช่นควรจะครอบคลุมกรณีที่ชัดเจนเชี่ยวชาญtemplate<> void f<>(int) {} โดยไม่ต้องinlineคำหลัก แต่ถึงอย่างนั้นการเปลี่ยนตัวinlineระบุบนเทมเพลตก็ไม่ได้สร้างความแตกต่างใด ๆ เพราะไม่ว่าคุณจะทำเครื่องหมายแม่แบบinlineหรือไม่ก็ไม่เกี่ยวข้อง
gnzlbg

34

มันไม่เกี่ยว เทมเพลตทั้งหมดมีอยู่แล้วinline- ไม่ต้องพูดถึงว่าในปี 2012 การใช้inlineคำหลักเพียงอย่างเดียวคือหยุดคอมไพเลอร์ที่บ่นเกี่ยวกับการละเมิด ODR คุณมีความถูกต้อง - คอมไพเลอร์รุ่นปัจจุบันของคุณจะรู้ว่าต้องอินไลน์อะไรด้วยตัวมันเองและอาจทำได้แม้กระทั่งระหว่างหน่วยการแปล


11
มาตรฐานไม่ได้ระบุว่าเทมเพลตทั้งหมดเป็นแบบอินไลน์
Sebastian Mach

16
@phresnel: แต่เทมเพลตมีความหมายเหมือนกับinlineฟังก์ชันที่ทำเครื่องหมายไว้ (นั่นคือคำจำกัดความที่เทียบเท่าหลายคำอาจถูกส่งผ่านไปยังตัวเชื่อมโยงซึ่งจะเลือกอย่างใดอย่างหนึ่ง) นั่นไม่ใช่การใส่อินไลน์เป็นหน้าที่ที่แท้จริงของinlineคำหลัก
Ben Voigt

2
@ BenVoigt: ฉันรู้เกี่ยวกับความหมาย ODR ของinline. อาจลองดูคำตอบของฉันด้านล่าง (หรือด้านบนขึ้นอยู่กับการจัดเรียงที่เลือก) สำหรับเทมเพลตที่ไม่ใช่เฉพาะทางแน่นอนว่าคุณคิดถูก แต่มันไม่เหมือนกันอย่างเป็นทางการ
Sebastian Mach

3
@DeadMG: ไม่มีข้อกำหนดใน C ++ ที่ต้องใช้เทมเพลตฟังก์ชันในไฟล์ส่วนหัว สามารถใช้งานได้ทุกที่ เพื่อแสดงถึงสิ่งนี้ฉันมักจะแนะนำให้ติดแท็กinlineสิ่งที่ควรจะเป็นแบบอินไลน์ โดยปกติจะไม่แตกต่างกัน แต่ในมาตรฐานจะไม่เหมือนกันและไม่ใช่แบบอินไลน์ทั้งหมด ฉันยอมรับจุดยืนของคุณที่บอกว่า "ไม่เกี่ยวข้อง" แต่ตามมาตรฐานแล้วเทมเพลตทั้งหมดไม่ใช่แบบอินไลน์สำหรับคุณในฐานะ C ++ เท่านั้น - ผู้ใช้ที่ปรากฏราวกับว่า
Sebastian Mach

7
ความคิดเห็นของคุณเกี่ยวกับคำตอบที่ได้รับการยอมรับว่าความเชี่ยวชาญที่ชัดเจนไม่ใช่แม่แบบ (ซึ่งเห็นได้ชัดหลังจากได้รับการบอกกล่าวเช่นนั้น .... ) อาจเป็นสิ่งที่มีประโยชน์ที่สุดในหน้านี้ คุณช่วยกรุณาเพิ่มคำตอบของคุณด้วยหรือไม่?
Kyle Strand

6

ตามที่คุณแนะนำinlineเป็นคำแนะนำสำหรับคอมไพเลอร์และไม่มีอะไรเพิ่มเติม สามารถเลือกที่จะเพิกเฉยหรือเลือกฟังก์ชันอินไลน์ที่ไม่ได้ทำเครื่องหมายไว้ในบรรทัด

การใช้inlineกับเทมเพลตเคยเป็นวิธีการ (ไม่ดี) ในการแก้ไขปัญหาที่แต่ละหน่วยคอมไพล์จะสร้างอ็อบเจ็กต์แยกต่างหากสำหรับคลาสเท็มเพลตเดียวกันซึ่งจะทำให้เกิดปัญหาการทำซ้ำในเวลาลิงก์ ด้วยการใช้inline(ฉันคิดว่า) การทำให้ชื่อแตกต่างออกไปซึ่งจะทำให้เกิดการปะทะกันของชื่อในเวลาเชื่อมโยง แต่ต้องเสียค่าใช้จ่ายของรหัสที่ป่องอย่างมาก  

Marshall Cline อธิบายที่นี่ดีกว่าที่ฉันทำได้


@Xeo: ไม่เคยเป็นอย่างนั้น ตรวจสอบที่นี่: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/…ฉันคิดว่ามีการเปลี่ยนแปลงเมื่อเร็ว ๆ นี้นั่นคือเหตุผลที่ฉันพูดถึงในอดีตกาล
ส่วนประกอบ 10

2
@Xeo: คุณช่วยชี้ให้ฉันดูส่วนของ The Standard ที่ระบุว่าเทมเพลตฟังก์ชันอยู่ในบรรทัดเสมอได้หรือไม่? เพราะพวกเขาไม่ได้
Sebastian Mach

@phresnel: น่าสนใจฉันสาบานได้ว่าฉันอ่านในมาตรฐาน บางทีฉันอาจผสมกับความจริงที่ว่าเทมเพลตฟังก์ชันได้รับการยกเว้นจาก ODR ( §14.5.5.1 p7 & p8) ฉันไม่ดีฉันลบความคิดเห็นที่ผิด
Xeo

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