Apakah masuk akal untuk menggunakan kata kunci sebaris dengan templat?

119

Karena templat didefinisikan di dalam tajuk dan kompilator dapat menentukan apakah sebaris fungsi menguntungkan, apakah masuk akal? Saya pernah mendengar bahwa kompiler modern tahu lebih baik kapan harus menyebariskan suatu fungsi dan mengabaikan inlinepetunjuk.


edit: Saya ingin menerima kedua jawaban tersebut, tetapi ini tidak mungkin. Untuk menutup masalah ini saya menerima jawaban phresnel , karena mendapat suara terbanyak dan dia secara resmi benar, tetapi seperti yang saya sebutkan di komentar, saya menganggap Puppy 's dan Komponen 10 jawaban sebagai jawaban yang benar juga, dari sudut pandang yang berbeda .

Masalahnya ada di semantik C ++, yang tidak ketat dalam hal inlinekata kunci dan sebaris. phresnel mengatakan "tulis sebaris jika Anda bersungguh-sungguh", tetapi apa yang sebenarnya dimaksud inlinetidak jelas karena ia berevolusi dari makna aslinya menjadi petunjuk yang "menghentikan penyusun mengomel tentang pelanggaran ODR" seperti yang dikatakan Puppy .

dokter
sumber

Jawaban:

96

Itu tidak relevan. Dan tidak, tidak setiap template fungsi inlinesecara default. Standar bahkan eksplisit tentang itu dalam spesialisasi eksplisit ([temp.expl.spec])

Memiliki yang berikut:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (diambil dari Spesialisasi Eksplisit):

#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

Kompilasi ini, dan 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

Tidak menyatakan inlinesaat melakukan pembuatan instance eksplisit juga dapat menyebabkan masalah.

Singkatnya : Untuk templat fungsi yang tidak terspesialisasi penuh, yaitu templat yang memuat setidaknya satu jenis yang tidak diketahui, Anda dapat menghilangkan inline, dan tidak menerima kesalahan, tetapi tetap saja tidak inline. Untuk spesialisasi penuh, yaitu yang hanya menggunakan tipe yang diketahui, Anda tidak dapat menghilangkannya.

Aturan praktis yang diusulkan : Tulis inlinejika Anda bersungguh-sungguh dan bersikaplah konsisten. Itu membuat Anda kurang memikirkan apakah akan atau tidak hanya karena Anda bisa. (Aturan praktis ini sesuai dengan Template C ++ Vandevoorde / Josuttis : Panduan Lengkap ).

Sebastian Mach
sumber
2
Seseorang bisa saja menulis, benar. Tapi itu tidak berarti inlineness, meski terlihat seperti itu. Vandevoorde dan Josuttis juga menyatakan hal itu dengan tepat di Template C ++: Panduan Lengkap
Sebastian Mach
43
Spesialisasi eksplisit bukanlah template.
Anak anjing
2
@DeadMG: Namun fungsi normal lebih disukai daripada spesialisasi penuh saat pencarian, jadi jika mereka bukan template, atau non-template, lalu apa?
Sebastian Mach
13
Jawaban ini salah. Spesialisasi eksplisit dari sebuah template adalah sebuah fungsi, bukan template. Fungsi itu tidak menjadi inlinehanya karena templat yang dikhususkan ditandai dengan inline. Jadi inlinepada template sama sekali tidak relevan. Apakah fungsi itu harus ada inlineatau tidak, tidak ada hubungannya dengan itu yang dihasilkan melalui spesialisasi template (dan ada jawaban yang lebih baik daripada alamat ini ketika digunakan inline). Jawaban @Puppy di bawah ini benar, yang ini salah. Menambahkan inlinetemplate tidak relevan, dan clang-tidysebenarnya akan menghapusnya.
gnzlbg
6
Selain itu, contoh ini hanya menampilkan masalah ODR untuk fungsi normal (perilaku yang tidak ada hubungannya dengan template). Untuk mencoba menunjukkan bahwa inlinetidak tidak relevan, misalnya harus mencakup kasus eksplisit mengkhususkan diri template<> void f<>(int) {} tanpa itu inlinekata kunci. Tetapi bahkan kemudian mengubah inlinepenentu pada templat tidak membuat perbedaan apa pun, karena apakah Anda menandai templat inlineatau tidak tidak relevan.
gnzlbg
34

Itu tidak relevan. Semua template sudah ada inline- belum lagi pada tahun 2012, satu-satunya penggunaan inlinekata kunci tersebut adalah untuk menghentikan penyusun yang mengeluh tentang pelanggaran ODR. Anda benar-benar benar- kompilator generasi sekarang Anda akan tahu apa yang harus disisipkan sendiri dan mungkin dapat melakukannya bahkan di antara unit terjemahan.

Anak anjing
sumber
11
Standar tidak menyatakan bahwa semua template sebaris.
Sebastian Mach
16
@phresnel: Namun template memiliki semantik yang sama dengan inlinefungsi yang ditandai (yaitu, beberapa definisi yang setara dapat diteruskan ke linker, yang akan memilih salah satu). Itu, bukan sebaris, adalah fungsi sebenarnya dari inlinekata kunci.
Ben Voigt
2
@ BenVoigt: Saya tahu tentang arti ODR inline. Mungkin bisa mengintip jawaban saya di bawah (atau di atas, tergantung penyortiran yang dipilih). Untuk templat yang tidak terspesialisasi, Anda tentu saja benar, tetapi secara formal tidak sama.
Sebastian Mach
3
@DeadMG: Tidak ada persyaratan di C ++ bahwa template fungsi harus diimplementasikan dalam file header; itu dapat diterapkan di mana saja. Untuk mencerminkan hal ini, saya cenderung merekomendasikan penandaan inlineapa yang seharusnya sebaris. Biasanya tidak ada bedanya, tetapi dalam bahasa standar, mereka tidak sama, dan tidak semuanya sejajar. Saya menerima pendapat Anda tentang hal itu dengan mengatakan "Ini tidak relevan", tetapi menurut standar, tidak semua template berada dalam baris, hanya untuk Anda sebagai pengguna C ++ - template tersebut tampak seolah-olah.
Sebastian Mach
7
Komentar Anda atas jawaban yang diterima bahwa spesialisasi eksplisit bukanlah template (yang jelas setelah diberi tahu, tentu saja ....) mungkin adalah hal yang paling membantu di halaman ini. Maukah Anda menambahkannya ke jawaban Anda juga?
Kyle Strand
6

Seperti yang Anda sarankan, inlineini adalah petunjuk untuk kompiler dan tidak lebih. Ia dapat memilih untuk mengabaikannya atau, memang, fungsi sebaris tidak ditandai sebaris.

Menggunakan inlinewith template dulunya merupakan cara (buruk) untuk mengatasi masalah bahwa setiap unit kompilasi akan membuat objek terpisah untuk kelas template yang sama yang kemudian akan menyebabkan masalah duplikasi pada waktu penautan. Dengan menggunakan inline(saya pikir) nama mangling berhasil berbeda yang membuat nama bentrok pada waktu tautan tetapi dengan mengorbankan kode yang sangat membengkak.  

Marshall Cline menjelaskan di sini lebih baik dari yang saya bisa.

Komponen 10
sumber
@ Xeo: Dulu tidak seperti itu. Lihat di sini: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… Saya berasumsi bahwa belakangan ini telah berubah, itulah mengapa saya berbicara dalam bentuk lampau.
Komponen 10
2
@ Xeo: Dapatkah Anda mengarahkan saya ke bagian The Standard yang menyatakan bahwa templat fungsi selalu sebaris? Sebab, mereka tidak.
Sebastian Mach
@phresnel: Menarik, saya berani bersumpah saya sudah membacanya di standar. Mungkin saya mencampurnya dengan fakta bahwa template fungsi dikecualikan dari ODR ( §14.5.5.1 p7 & p8). Saya buruk, saya menghapus komentar yang salah.
Xeo
@Component 10 Mengapa menurut Anda itu cara yang buruk untuk menyelesaikan masalah kompilasi
Kapil