สมาชิก const int แบบคงที่และการอ้างอิงที่ไม่ได้กำหนด

ฉันใช้ gcc 4.7.3 สำหรับแพลตฟอร์ม ARM เพื่อรวบรวมโค้ดของฉัน ฉันมีหลายชั้นเรียนเช่นนี้:

// types.h
enum Types
{
    kType1,
    kType2
    // ...
};

// d1.h
class D1 : public Base
{
public:
    static const int type = kType1;
    // ...
};

// d2.h
class D2 : public Base
{
public:
    static const int type = kType2;
    // ...
};

ฉันใช้คลาสเหล่านั้นที่ไหนสักแห่งในแหล่งที่มา:

MyObject obj;
doSomething<D1>(obj);
doSomething<D2>(obj);

// other.cpp
class Foo
{
    template<typename T>
    void doSomething(MyObject obj)
    {
        mm_.insert(std::multimap<int, MyObject>::value_type(T::type, obj));
    }
};

และรับข้อความถัดไป (ระหว่างการเชื่อมโยง):

undefined reference to `D1::kType`
undefined reference to `D2::kType`
// more messages of this type

ตกลง. ถ้าฉันเปลี่ยนฟังก์ชัน do_something เช่นนี้:

template<typename T>
void doSomething(MyObject obj)
{
    mm_.insert(std::multimap<int, MyObject>::value_type( (int) T::type, obj));
}

มันคอมไพล์ตกลง แต่ทำไม? ไม่พบสิ่งใดในมาตรฐานเกี่ยวกับเรื่องนี้ ใครมีความคิดเกี่ยวกับสิ่งที่เกิดขึ้น?

ขอบคุณ.

P.S.

การแก้ไขนี้

 // d1.cpp
 const int D1::kType;

ใช้งานได้เช่นกัน แต่คาดว่าจะเป็นเช่นนั้น

พี.พี.เอส. คำตอบจะค่อนข้างชัดเจนในกรณีที่ใช้การอ้างอิงหรือตัวชี้ไปที่ T::type แต่ฉันไม่เห็นสิ่งใดที่ต้องใช้การอ้างอิงหรือ ptr AFAIK std::multimap::value_type รับอาร์กิวเมนต์ตามค่า (ไม่ใช่การอ้างอิงหรือ ptr)


person maverik    schedule 03.07.2013    source แหล่งที่มา
comment
คุณไม่ควรอ้างอิง T::type และไม่ใช่ T::kType ใช่หรือไม่   -  person Timo Geusch    schedule 03.07.2013
comment
@TimoGeusch ใช่ขอบคุณ ที่ตายตัว   -  person maverik    schedule 03.07.2013
comment
คุณแน่ใจหรือว่าสิ่งที่ Timo ชี้ให้เห็นไม่สามารถแก้ไขปัญหาได้จริง เนื่องจากดูเหมือนว่าตัวเชื่อมโยงกำลังมองหา D1::kType ซึ่งเป็นสิ่งที่เทมเพลตของคุณขอ   -  person Mats Petersson    schedule 03.07.2013
comment
@ MatsPetersson มันเป็นเพียงการพิมพ์ผิดในคำถาม รหัสจริงใช้สมาชิกที่ถูกต้อง   -  person maverik    schedule 03.07.2013
comment
คุณอาจต้องโพสต์โค้ดจริง เนื่องจากโค้ดด้านบนดูไม่เป็นอันตรายและโอเค อย่างน้อยก็สำหรับฉัน   -  person Timo Geusch    schedule 03.07.2013
comment
คำถามที่เกี่ยวข้อง   -  person maverik    schedule 03.07.2013
comment
@maverik โปรดระบุ SSCCE ฉันพยายามขยายส่วนที่คุณทิ้งไว้ให้เรา แต่ gcc คอมไพล์ได้ค่อนข้างดี: ideone.com/CTu1UD - ดังนั้น gcc-4.7.2 จึงไม่สามารถมองเห็นข้อผิดพลาดได้ อย่างน้อยเราก็ทำไม่ได้โดยการดูโค้ดและเดาว่ามีอะไรหายไป   -  person Arne Mertz    schedule 03.07.2013
comment
@TimoGeusch น่าเสียดายที่มันใหญ่พอและยากที่จะตัดให้เป็นตัวอย่างที่คอมไพล์ได้น้อยที่สุด แต่ฉันจะพยายาม   -  person maverik    schedule 03.07.2013
comment
ในการตัดมันออก มีโอกาสค่อนข้างดีที่คุณจะพบปัญหาที่แท้จริง - มีแนวโน้มว่าจะพิมพ์ผิดคล้ายกับที่คุณพบตอนนี้   -  person Mats Petersson    schedule 03.07.2013
comment
std::multimap<T,U>::value_type คือ std::pair<const T,U> ซึ่งตัวสร้างใช้เวลา const& T, const& U FWIW.   -  person rici    schedule 03.07.2013
comment
ปัญหาที่แท้จริงคือโค้ดนี้หลายส่วนอยู่ในไฟล์ส่วนหัว ดังนั้นจึงเป็นเรื่องยากพอที่จะยกตัวอย่างง่ายๆ เพื่อแสดงกรณีนี้ และถ้าฉันใส่สิ่งเหล่านั้นลงใน cpp สิ่งนี้ก็คงไม่เกี่ยวข้อง   -  person maverik    schedule 03.07.2013
comment
@rici: ตอนนี้มันสมเหตุสมผลแล้ว (และฉันเข้าใจว่าทำไมนักแสดงถึงแก้ปัญหาได้)   -  person maverik    schedule 03.07.2013


คำตอบ (1)


// d1.cpp
const int D1::kType;

// d2.cpp
const int D2::kType;

คือคำตอบ

//d1.h
public:
    static const int type = kType1;

เหมือนกับฟังก์ชันต้นแบบ มันถูกคอมไพล์ลงในอ็อบเจ็กต์แทรกทุกอัน (ไฟล์ cpp) ที่มีส่วนหัว ดังนั้นเนื่องจากกฎ ODR จึงไม่สงวนพื้นที่หน่วยความจำจริง ๆ ไม่เช่นนั้นตัวเชื่อมโยงจะพบอินสแตนซ์จำนวนมากของ ตัวแปรในทุกหน่วยการคอมไพล์ซึ่งรวมถึงส่วนหัว

ดังนั้นคุณจึงต้องมีหน่วยการคอมไพล์หนึ่งหน่วย (ไฟล์ cpp) ซึ่งกำหนดพื้นที่หน่วยความจำจริงที่จะใช้สำหรับค่าคงที่คลาสที่พบในส่วนหัวที่ใช้หลายครั้ง

person Strings    schedule 20.09.2013