Adakah yang bisa menjelaskan mengapa kode berikut tidak dapat dikompilasi? Setidaknya pada g ++ 4.2.4.
Dan yang lebih menarik, mengapa itu akan dikompilasi ketika saya melemparkan ANGGOTA ke int?
#include <vector>
class Foo {
public:
static const int MEMBER = 1;
};
int main(){
vector<int> v;
v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER'
v.push_back( (int) Foo::MEMBER ); // OK
return 0;
}
Jawaban:
Anda harus benar-benar mendefinisikan anggota statis di suatu tempat (setelah definisi kelas). Coba ini:
Itu harus menyingkirkan referensi yang tidak ditentukan.
sumber
Masalahnya muncul karena bentrokan menarik dari fitur C ++ baru dan apa yang Anda coba lakukan. Pertama, mari kita lihat
push_back
tanda tangannya:Itu mengharapkan referensi ke objek tipe
T
. Di bawah sistem inisialisasi yang lama, anggota semacam itu ada. Sebagai contoh, kode berikut mengkompilasi dengan baik:Ini karena ada objek aktual di suatu tempat yang memiliki nilai yang tersimpan di dalamnya. Namun, jika Anda beralih ke metode baru menentukan anggota const statis, seperti yang Anda miliki di atas,
Foo::MEMBER
tidak lagi menjadi objek. Ini konstan, agak mirip dengan:Tetapi tanpa sakit kepala makro preprocessor (dan dengan keamanan jenis). Itu berarti bahwa vektor, yang mengharapkan referensi, tidak bisa mendapatkannya.
sumber
(int)
pemeran) terjadi di unit terjemahan dengan visibilitas sempurna dari konstanta, danFoo::MEMBER
tidak lagi digunakan odr . Ini berbeda dengan pemanggilan fungsi pertama, di mana referensi diedarkan dan dievaluasi di tempat lain.void push_back( const T& value );
?const&
Dapat mengikat dengan nilai.Standar C ++ memerlukan definisi untuk anggota const statis Anda jika definisi tersebut diperlukan.
Definisi tersebut diperlukan, misalnya jika alamatnya digunakan.
push_back
mengambil parameternya dengan referensi const, dan oleh karena itu compiler memerlukan alamat anggota Anda dan Anda perlu mendefinisikannya di namespace.Ketika Anda secara eksplisit melemparkan konstanta, Anda sedang membuat sementara dan ini sementara yang terikat pada referensi (di bawah aturan khusus dalam standar).
Ini adalah kasus yang sangat menarik, dan saya benar-benar berpikir itu layak mengangkat masalah sehingga std diubah untuk memiliki perilaku yang sama untuk anggota tetap Anda!
Meskipun, dalam cara yang aneh ini bisa dilihat sebagai penggunaan sah operator '+' unary. Pada dasarnya hasil dari nilai
unary +
adalah rvalue dan karenanya aturan untuk mengikat nilai rujukan ke referensi const berlaku dan kami tidak menggunakan alamat anggota const statis kami:sumber
push_back
adalahconst &
. Menggunakan anggota secara langsung mengakibatkan anggota terikat pada referensi, yang mengharuskannya memiliki alamat. Namun, menambahkan+
menciptakan sementara dengan nilai anggota. Referensi kemudian mengikat untuk sementara itu daripada mengharuskan anggota memiliki alamat.Aaa.h
Aaa.cpp
sumber
Tidak tahu mengapa pemeran bekerja, tetapi Foo :: MEMBER tidak dialokasikan hingga pertama kali Foo dimuat, dan karena Anda tidak pernah memuatnya, itu tidak pernah dialokasikan. Jika Anda memiliki referensi ke Foo di suatu tempat, itu mungkin akan berhasil.
sumber
Dengan C ++ 11, hal di atas dimungkinkan untuk tipe dasar sebagai
Bagian ini
constexpr
menciptakan ekspresi statis yang bertentangan dengan variabel statis - dan itu berperilaku seperti definisi metode inline yang sangat sederhana. Pendekatan ini terbukti sedikit goyah dengan constexprs C-string di dalam kelas template, meskipun.sumber
Mengenai pertanyaan kedua: push_ref mengambil referensi sebagai parameter, dan Anda tidak dapat memiliki referensi untuk memeber const statis dari kelas / struct. Setelah Anda memanggil static_cast, variabel sementara dibuat. Dan referensi ke objek ini dapat dilewati, semuanya berfungsi dengan baik.
Atau setidaknya kolega saya yang menyelesaikan ini mengatakan demikian.
sumber