เหตุใดอาร์เรย์ของการอ้างอิงที่ผิดกฎหมาย


149

รหัสต่อไปนี้ไม่ได้รวบรวม

int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};

มาตรฐาน C ++ พูดถึงอะไรเกี่ยวกับเรื่องนี้

ฉันรู้ว่าฉันสามารถประกาศคลาสที่มีการอ้างอิงจากนั้นสร้างอาร์เรย์ของคลาสนั้นตามที่แสดงด้านล่าง แต่ฉันอยากรู้ว่าทำไมรหัสด้านบนไม่ได้รวบรวม

struct cintref
{
    cintref(const int & ref) : ref(ref) {}
    operator const int &() { return ref; }
private:
    const int & ref;
    void operator=(const cintref &);
};

int main() 
{
  int a=1,b=2,c=3;
  //typedef const int &  cintref;
  cintref arr[] = {a,b,c,8};
}

มันเป็นไปได้ที่จะใช้struct cintrefแทนconst int &การจำลองอาร์เรย์ของการอ้างอิง


1
แม้ว่าอาเรย์นั้นจะถูกต้อง แต่การจัดเก็บค่า '8' ดิบในนั้นจะไม่ทำงาน หากคุณทำ "intlink value = 8;" มันจะตายอย่างน่ากลัวเพราะมันเพิ่งแปลเป็น "const int & value = 8;" การอ้างอิงจะต้องอ้างอิงตัวแปร
Grant Peters

3
intlink value = 8;ทำงานได้ดี ตรวจสอบว่าคุณไม่เชื่อ
Alexey Malistov

7
ดังที่ Alexey ชี้ให้เห็นมันเป็นสิ่งที่สมบูรณ์แบบที่จะผูกค่า rvalue กับค่าอ้างอิง const
avakar

1
สิ่งที่ไม่ได้operator=ทำงานก็คือว่า ไม่สามารถอ้างอิงซ้ำได้ หากคุณต้องการจริงๆความหมายดังกล่าว - แม้ว่าฉันไม่พบบุคคลสถานการณ์ที่พวกเขากำลังมีประโยชน์จริง - แล้วstd::reference_wrapperจะเป็นวิธีที่จะทำมันขณะที่มันจริงเก็บชี้ แต่ให้อ้างอิงเหมือนoperatorและไม่อนุญาตให้ reseating แต่ฉันจะใช้พอยน์เตอร์!
underscore_d

1
ตัวดำเนินการ = เป็นแบบส่วนตัวและไม่ได้ใช้งานสิ่งที่อยู่ใน C ++ 11 คือ = ลบ
Jimmy Hartzell

คำตอบ:


148

ตอบคำถามของคุณเกี่ยวกับมาตรฐานฉันสามารถอ้างอิงมาตรฐาน C ++ §8.3.2 / 4 :

จะไม่มีการอ้างอิงถึงการอ้างอิงไม่มีอาร์เรย์ของการอ้างอิงและไม่มีตัวชี้ไปยังการอ้างอิง


32
มีอะไรให้พูดอีกเยอะ?
พูดได้หลายภาษา

9
ควรมีอาร์เรย์ของการอ้างอิงด้วยเหตุผลเดียวกันกับที่เรามีอาร์เรย์ของพอยน์เตอร์ข้อมูลเดียวกัน แต่มีการจัดการที่แตกต่างกันไม่ใช่?
neu-rah

6
หากนักพัฒนาคอมไพเลอร์ตัดสินใจว่าเป็นส่วนขยายเพื่ออนุญาตให้มีอาร์เรย์ของการอ้างอิงแล้วมันจะประสบความสำเร็จหรือไม่ หรือมีปัญหาบางอย่างจริง - อาจเป็นรหัสคลุมเครือ - ซึ่งจะทำให้สับสนเกินไปที่จะกำหนดส่วนขยายนี้
Aaron McDaid

23
@AaronMcDaid ฉันคิดว่าเหตุผลที่แท้จริง - ซึ่งขาดไปอย่างเด่นชัดจากการสนทนานี้และที่คล้ายกัน - คือถ้ามีการอ้างอิงหลายวิธีหนึ่งจะ disambiguate ระหว่างที่อยู่ขององค์ประกอบและที่อยู่ของผู้อ้างอิงได้อย่างไร การคัดค้านทันทีถึง 'คุณไม่สามารถใส่การอ้างอิงในอาร์เรย์ / คอนเทนเนอร์ / อะไรก็ตาม' คือคุณสามารถใส่structสมาชิกที่มีการอ้างอิงเพียงอย่างเดียว แต่เมื่อทำเช่นนี้คุณจะได้ทั้งข้อมูลอ้างอิงและวัตถุแม่เป็นชื่อ ... ซึ่งตอนนี้หมายความว่าคุณสามารถระบุที่อยู่ที่คุณต้องการได้อย่างชัดเจน ดูเหมือนชัดเจน ... ทำไมไม่มีใครพูด
underscore_d

95
@polyglot What more is there to say?เหตุผลทำไม ? ฉันทุกคนเกี่ยวกับมาตรฐาน แต่เพียงแค่อ้างถึงและสมมติว่านั่นคือจุดสิ้นสุดของการสนทนาดูเหมือนจะเป็นวิธีที่แน่นอนในการทำลายความคิดที่สำคัญของผู้ใช้พร้อมกับศักยภาพในการพัฒนาภาษาเช่นเกินขอบเขตของการละเลยหรือ ข้อ จำกัด เทียม มีมากเกินไป 'เพราะมาตรฐานบอกว่า' ที่นี่ - และไม่เพียงพอ 'และมีเหตุผลที่จะพูดอย่างนั้นเนื่องจากเหตุผลในทางปฏิบัติต่อไปนี้' ฉันไม่รู้ว่าทำไม upvotes ไหลจึงกระตือรือร้นที่จะตอบว่าพูดอดีตโดยไม่ต้องพยายามสำรวจหลัง
underscore_d

64

การอ้างอิงไม่ใช่วัตถุ พวกเขาไม่ได้จัดเก็บข้อมูลของตัวเองพวกเขาเพียงแค่อ้างอิงวัตถุที่มีอยู่ ด้วยเหตุนี้จึงไม่มีเหตุผลที่จะมีอาร์เรย์ของการอ้างอิง

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

แก้ไข:ในฐานะที่เป็นบันทึก jia3ep ในส่วนมาตรฐานในการประกาศมีข้อห้ามที่ชัดเจนเกี่ยวกับอาร์เรย์ของการอ้างอิง


6
การอ้างอิงมีลักษณะเหมือนกันกับตัวชี้คงที่ดังนั้นพวกเขาจึงใช้หน่วยความจำ (ที่เก็บข้อมูล) เพื่อชี้ไปที่บางสิ่งบางอย่าง
inazaruk

7
ไม่จำเป็น คอมไพเลอร์อาจสามารถหลีกเลี่ยงการจัดเก็บที่อยู่ถ้ามันเป็นการอ้างอิงถึงวัตถุภายในเครื่องเช่น
EFraim

4
ไม่จำเป็น. การอ้างอิงในโครงสร้างมักจะใช้ที่เก็บข้อมูลบางส่วน การอ้างอิงในท้องถิ่นมักจะไม่ทำ ไม่ว่าจะด้วยวิธีใดในความหมายมาตรฐานที่เข้มงวดการอ้างอิงไม่ใช่วัตถุและ (นี่เป็นเรื่องใหม่สำหรับฉัน) การอ้างอิงที่มีชื่อไม่ใช่ตัวแปรจริงๆ
CB Bailey

26
ใช่ แต่นี่คือรายละเอียดการใช้งาน วัตถุใน C ++ แบบเป็นภูมิภาคที่พิมพ์ในการจัดเก็บ การอ้างอิงไม่ใช่วัตถุอย่างชัดเจนและไม่รับประกันว่าจะใช้พื้นที่เก็บข้อมูลในบริบทเฉพาะใด ๆ
CB Bailey

9
วางไว้ในลักษณะนี้: คุณสามารถมีโครงสร้างของอะไร แต่ 16 refs เพื่อ foo's และใช้ในลักษณะเดียวกับที่ฉันต้องการใช้อาร์เรย์ refs ของฉัน - ยกเว้นว่าคุณไม่สามารถจัดทำดัชนีในการอ้างอิง 16 foo . นี่คือหูดภาษา IMHO
greggo

28

นี่คือการสนทนาที่น่าสนใจ การเรียงลำดับของการอ้างอิงอย่างชัดเจนนั้นผิดกฎหมายโดยสิ้นเชิง แต่ IMHO เป็นสาเหตุที่ทำให้ไม่ง่ายเหมือนกับการพูดว่า "ไม่ใช่วัตถุ" หรือ "ไม่มีขนาด" ฉันจะชี้ให้เห็นว่าอาร์เรย์ตัวเองไม่ใช่วัตถุที่เต็มเปี่ยมใน C / C ++ - ถ้าคุณคัดค้านลองใช้แม่แบบ stl บางคลาสโดยใช้อาร์เรย์เป็นพารามิเตอร์แม่แบบ 'class' และดูว่าเกิดอะไรขึ้น คุณไม่สามารถคืนค่ากำหนดส่งผ่านเป็นพารามิเตอร์ได้ (อาร์เรย์ param ถือเป็นตัวชี้) แต่มันถูกกฎหมายที่จะทำให้อาร์เรย์ของอาร์เรย์ การอ้างอิงมีขนาดที่คอมไพเลอร์สามารถและต้องคำนวณ - คุณไม่สามารถกำหนดขนาดของการอ้างอิงได้ แต่คุณสามารถสร้างโครงสร้างที่ไม่มีอะไรนอกจากการอ้างอิง มันจะมีขนาดเพียงพอที่จะมีตัวชี้ทั้งหมดที่ใช้การอ้างอิง คุณสามารถ'

struct mys {
 int & a;
 int & b;
 int & c;
};
...
int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs.a += 3  ;  // add 3 to ivar1

ในความเป็นจริงคุณสามารถเพิ่มบรรทัดนี้ในนิยาม struct

struct mys {
 ...
 int & operator[]( int i ) { return i==0?a : i==1? b : c; }
};

... และตอนนี้ฉันมีบางอย่างที่ดูเหมือนเป็นจำนวนมาก:

int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs[1] = my_refs[2]  ;  // copy arr[12] to ivar2
&my_refs[0];               // gives &my_refs.a == &ivar1

ทีนี้นี่ไม่ใช่อาเรย์จริงมันเป็นโอเปอเรเตอร์ที่เกินกำลัง มันจะไม่ทำสิ่งต่าง ๆ ที่อาร์เรย์ทำตามปกติเช่น sizeof (arr) / sizeof (arr [0]) เป็นต้น แต่มันก็เป็นสิ่งที่ฉันต้องการให้มีการอ้างอิงมากมายที่ต้องทำด้วยกฎหมาย C ++ ที่สมบูรณ์แบบ ยกเว้น (a) เป็นความเจ็บปวดในการตั้งค่าสำหรับองค์ประกอบมากกว่า 3 หรือ 4 รายการและ (b) กำลังทำการคำนวณโดยใช้กลุ่ม?: ซึ่งสามารถทำได้โดยใช้การจัดทำดัชนี (ไม่ใช่การสร้างดัชนี C-pointer-calcul-semantics ปกติ แต่การจัดทำดัชนียังคงมีอยู่) ฉันต้องการดู 'อาร์เรย์ของการอ้างอิง' ที่ จำกัด มากซึ่งสามารถทำได้จริง เช่นอาร์เรย์ของการอ้างอิงจะไม่ถือว่าเป็นอาร์เรย์ทั่วไปของสิ่งต่าง ๆ ที่เป็นการอ้างอิง แต่มันจะเป็น 'อาร์เรย์ของการอ้างอิง' ใหม่ ทำกับแม่แบบ)

สิ่งนี้อาจใช้ได้ถ้าคุณไม่รังเกียจสิ่งที่น่ารังเกียจเช่นนี้: ให้เรียงใหม่ '* นี่' เป็นอาร์เรย์ของ int * และกลับการอ้างอิงที่ทำจากหนึ่ง: (ไม่แนะนำ แต่มันแสดงให้เห็นว่า 'อาร์เรย์' ที่เหมาะสม จะทำงาน):

 int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }

1
คุณสามารถทำได้ใน C ++ 11 std::tuple<int&,int&,int&> abcref = std::tie( a,b,c)- ซึ่งสร้าง "อาร์เรย์" ของการอ้างอิงที่สามารถสร้างดัชนีได้โดยค่าคงที่เวลาคอมไพล์โดยใช้ std :: get std::array<int&,3> abcrefarr = std::tie( a,b,c)แต่คุณไม่สามารถทำ อาจจะมีวิธีการทำที่ฉันไม่รู้ ดูเหมือนว่าฉันควรมีวิธีการเขียนความเชี่ยวชาญstd::array<T&,N>ที่สามารถทำเช่นนี้ - และฟังก์ชั่นstd::tiearray(...)ที่ส่งกลับอย่างใดอย่างหนึ่ง (หรืออนุญาตให้std::array<T&,N>ยอมรับ initializer ที่มีที่อยู่ = {& v1, & v2 ฯลฯ })
greggo

ข้อเสนอของคุณโง่ (IMO) และบรรทัดสุดท้ายของคุณถือว่า int สามารถถือเป็นตัวชี้ (โดยปกติจะเป็นเท็จอย่างน้อยที่ฉันทำงาน) แต่นี่เป็นคำตอบเดียวที่นี่พร้อมเหตุผลที่ถูกต้องเพราะเหตุใดอาร์เรย์ของการอ้างอิงจึงถูกห้ามดังนั้น +1
Nemo

@Nemo มันไม่ได้มีวัตถุประสงค์เพื่อเป็นข้อเสนอ แต่เพียงเพื่อแสดงให้เห็นว่าการทำงานของสิ่งนั้นไม่ได้เป็นเรื่องไร้สาระบนใบหน้า ฉันสังเกตเห็นในความคิดเห็นล่าสุดของฉันว่า c ++ มีสิ่งที่ใกล้เคียง นอกจากนี้บรรทัดสุดท้ายที่คุณอ้างถึงถือว่าหน่วยความจำที่ใช้การอ้างอิงไปยัง int สามารถใช้นามแฝงเป็นประโยชน์เป็นตัวชี้ไป - int - โครงสร้างที่มีการอ้างอิงไม่ใช่ ints - และที่มีแนวโน้มที่จะเป็นจริง ฉันไม่ได้อ้างว่าเป็นอุปกรณ์พกพา (หรือปลอดภัยจากกฎ 'พฤติกรรมที่ไม่ได้กำหนด') มันหมายถึงการแสดงให้เห็นว่าการจัดทำดัชนีสามารถใช้ภายใต้กระโปรงเพื่อหลีกเลี่ยงการทั้งหมด?:
greggo

ยุติธรรมพอสมควร แต่ฉันคิดว่าความคิดนี้เป็น "ไร้สาระบนใบหน้าของมัน" และนี่คือสาเหตุที่ไม่อนุญาตให้มีการอ้างอิงอาร์เรย์ อาเรย์คืออันดับแรกและสำคัญที่สุดคือคอนเทนเนอร์ คอนเทนเนอร์ทั้งหมดต้องการชนิดตัววนซ้ำสำหรับอัลกอริธึมมาตรฐานที่จะใช้ ชนิดตัววนซ้ำสำหรับ "อาร์เรย์ของ T" โดยปกติคือ "T *" ชนิดตัววนซ้ำสำหรับอาร์เรย์ของการอ้างอิงคืออะไร จำนวนการแฮ็กภาษาที่ต้องใช้ในการจัดการกับปัญหาเหล่านี้ทั้งหมดนั้นไร้สาระสำหรับฟีเจอร์ที่ไร้ประโยชน์เป็นหลัก จริง ๆ แล้วฉันอาจจะตอบคำถามนี้ด้วยตัวเอง :-)
Nemo

@Nemo มันไม่จำเป็นต้องเป็นส่วนหนึ่งของภาษาหลักดังนั้นประเภทตัววนซ้ำนั้นเป็น 'กำหนดเอง' ไม่ใช่เรื่องใหญ่ คอนเทนเนอร์ชนิดต่าง ๆ ทั้งหมดมีชนิดตัววนซ้ำ ในกรณีนี้ตัวทำซ้ำที่ถูกอ้างอิงจะอ้างอิงถึง objs เป้าหมายไม่ใช่การอ้างอิงในอาเรย์ซึ่งสอดคล้องกับพฤติกรรมของอาเรย์อย่างสมบูรณ์ มันอาจยังคงต้องใช้พฤติกรรม C ++ ใหม่เพื่อสนับสนุนเป็นเทมเพลตstd::array<T,N>รหัสแอพที่กำหนดได้ง่ายและง่ายไม่ได้ถูกเพิ่มไปยัง std :: จนถึง c ++ 11 น่าจะเป็นเพราะมันกระปมกระเปาที่จะไม่มีสิ่งนี้ สิ่งที่ต้องทำ= {1,2,3};คือการที่ 'ภาษาแฮ็ค'?
greggo

28

ความคิดเห็นต่อการแก้ไขของคุณ:

std::reference_wrapperทางออกที่ดีคือ

รายละเอียด: http://www.cplusplus.com/reference/functional/reference_wrapper/

ตัวอย่าง:

#include <iostream>
#include <functional>
using namespace std;

int main() {
    int a=1,b=2,c=3,d=4;
    using intlink = std::reference_wrapper<int>;
    intlink arr[] = {a,b,c,d};
    return 0;
}

สวัสดีนี่ได้รับการกล่าวกลับใน 09. เคล็ดลับค้นหาโพสต์ใหม่ :)
Stígandr

9
โพสต์เก่า แต่ไม่ใช่ทุกคนที่รู้วิธีแก้ปัญหาด้วย reference_wrapper ผู้คนจำเป็นต้องอ่านเรื่อง STL และ STDlib ของ C ++ 11
คุณจะ

reference_wrapperนี้จะช่วยให้การเชื่อมโยงและโค้ดตัวอย่างที่มากกว่าแค่การกล่าวถึงชื่อของชั้น
David Stone

12

อาร์เรย์สามารถแปลงเป็นตัวชี้ได้โดยปริยายและตัวชี้ไปยังการอ้างอิงนั้นผิดกฎหมายใน C ++


11
มันเป็นความจริงที่คุณไม่สามารถมีตัวชี้ไปยังการอ้างอิง แต่นี่ไม่ใช่เหตุผลที่คุณไม่สามารถมีอาร์เรย์ของการอ้างอิง ค่อนข้างพวกเขาทั้งสองอาการของความจริงที่ว่าการอ้างอิงไม่ใช่วัตถุ
Richard Corden

1
struct ไม่สามารถมีอะไรได้นอกจากการอ้างอิงและมันจะมีขนาดตามสัดส่วนกับจำนวนของพวกเขา หากคุณมีอาร์เรย์ของ refs 'arr' การแปลง array-to-pointer ปกติจะไม่สมเหตุสมผลเนื่องจาก 'pointer-to-reference' ไม่สมเหตุสมผล แต่มันก็สมเหตุสมผลที่จะใช้ arr [i] ในลักษณะเดียวกับ st.ref เมื่อ 'st' เป็น struct ที่มีการอ้างอิง อืมมม แต่ & arr [0] จะให้ที่อยู่ของวัตถุอ้างอิงแรกและ & arr [1] - & arr [0] จะไม่เหมือนกับ & arr [2] - & arr [1] - มันจะสร้างความแปลกประหลาดมากมาย
greggo

11

ให้int& arr[] = {a,b,c,8};ไว้คือsizeof(*arr)อะไร

ทุกที่อื่นอ้างอิงได้รับการปฏิบัติในฐานะที่เป็นเพียงแค่สิ่งที่ตัวเองดังนั้นก็ควรจะsizeof(*arr) sizeof(int)แต่นี่จะทำให้ตัวคำนวณอาร์เรย์ของอาเรย์ทางคณิตศาสตร์นั้นผิด (โดยสมมติว่าการอ้างอิงนั้นไม่ใช่ความกว้างเท่ากันคือ ints) เพื่อกำจัดความกำกวมมันเป็นสิ่งต้องห้าม


อ๋อ คุณไม่สามารถจัดเรียงของบางอย่างได้เว้นแต่จะมีขนาด ขนาดของการอ้างอิงคืออะไร?
David Schwartz

4
@DavidSchwartz ทำให้structสมาชิกที่มีการอ้างอิงเท่านั้นและหา .. ?
underscore_d

3
นี่ควรเป็นคำตอบที่ได้รับการยอมรับไม่ใช่คำอวดรู้ที่โง่เขลาเพียงแค่โยนมาตรฐานที่โอพี
Tyson Jacobs

อาจจะมีการพิมพ์ผิด "สมมติว่าการอ้างอิงไม่ใช่ความกว้างเดียวกันคือ ints" ควรเป็น "โดยสมมติว่าการอ้างอิงไม่ใช่ความกว้างเดียวกันกับ ints" เปลี่ยนเป็นจะเป็น
zhenguoli

แต่รอด้วยตรรกะนี้คุณไม่สามารถมีตัวแปรสมาชิกอ้างอิงได้
Tyson Jacobs

10

เพราะอย่างที่หลายคนพูดที่นี่การอ้างอิงไม่ใช่วัตถุ พวกเขาเป็นเพียงนามแฝง True ตัวแปลบางตัวอาจนำมาใช้เป็นพอยน์เตอร์ แต่มาตรฐานไม่ได้บังคับ / ระบุว่า และเนื่องจากการอ้างอิงไม่ใช่วัตถุคุณจึงไม่สามารถชี้ไปที่พวกเขาได้ การจัดเก็บองค์ประกอบในอาเรย์หมายความว่ามีที่อยู่ของดัชนีอยู่บ้าง (กล่าวคือชี้ไปที่องค์ประกอบที่ดัชนีหนึ่ง) และนั่นคือสาเหตุที่คุณไม่สามารถมีอาร์เรย์ของการอ้างอิงเพราะคุณไม่สามารถชี้ไปที่พวกเขา

ใช้เพิ่ม :: reference_wrapper หรือเพิ่ม :: tuple แทน หรือเพียงแค่พอยน์เตอร์


5

ฉันเชื่อว่าคำตอบนั้นง่ายมากและเกี่ยวข้องกับกฎความหมายของการอ้างอิงและวิธีจัดการอาร์เรย์ใน C ++

กล่าวโดยย่อ: การอ้างอิงสามารถพิจารณาได้ว่าเป็นโครงสร้างที่ไม่มีตัวสร้างเริ่มต้นดังนั้นจึงใช้กฎเดียวกันทั้งหมด

1) ความหมายการอ้างอิงไม่มีค่าเริ่มต้น การอ้างอิงสามารถสร้างได้โดยการอ้างอิงบางสิ่งเท่านั้น การอ้างอิงไม่มีค่าที่จะแสดงถึงการขาดการอ้างอิง

2) เมื่อจัดสรรอาเรย์ขนาด X โปรแกรมจะสร้างคอลเลกชันของออบเจ็กต์ที่เริ่มต้น เนื่องจากการอ้างอิงไม่มีค่าเริ่มต้นการสร้างอาร์เรย์ดังกล่าวจึงผิดกฎหมาย

กฎนี้ใช้กับโครงสร้าง / คลาสที่ไม่มีคอนสตรัคเตอร์เริ่มต้นด้วย ตัวอย่างโค้ดต่อไปนี้ไม่ได้รวบรวม:

struct Object
{
    Object(int value) { }
};

Object objects[1]; // Error: no appropriate default constructor available

1
คุณสามารถสร้างอาร์เรย์ของคุณเพียงแค่ต้องทำให้แน่ใจว่าจะเริ่มต้นพวกเขาทั้งหมด:Object Object objects[1] = {Object(42)};ในขณะเดียวกันคุณไม่สามารถสร้างอาร์เรย์ของการอ้างอิงได้แม้ว่าคุณจะเริ่มต้นการอ้างอิงทั้งหมด
Anton3

4

คุณสามารถเข้าใกล้กับโครงสร้างเทมเพลตนี้ได้พอสมควร อย่างไรก็ตามคุณต้องเริ่มต้นด้วยนิพจน์ที่เป็นตัวชี้ไปยัง T แทนที่จะเป็น T และถึงแม้ว่าคุณสามารถสร้าง 'fake_constref_array' ได้อย่างง่ายดายในทำนองเดียวกันคุณจะไม่สามารถผูกค่าดังกล่าวกับค่า rvalues ​​เช่นเดียวกับในตัวอย่างของ OP ('8');

#include <stdio.h>

template<class T, int N> 
struct fake_ref_array {
   T * ptrs[N];
  T & operator [] ( int i ){ return *ptrs[i]; }
};

int A,B,X[3];

void func( int j, int k)
{
  fake_ref_array<int,3> refarr = { &A, &B, &X[1] };
  refarr[j] = k;  // :-) 
   // You could probably make the following work using an overload of + that returns
   // a proxy that overloads *. Still not a real array though, so it would just be
   // stunt programming at that point.
   // *(refarr + j) = k  
}

int
main()
{
    func(1,7);  //B = 7
    func(2,8);     // X[1] = 8
    printf("A=%d B=%d X = {%d,%d,%d}\n", A,B,X[0],X[1],X[2]);
        return 0;
}

-> A = 0 B = 7 X = {0,8,0}


2

วัตถุอ้างอิงไม่มีขนาด ถ้าคุณเขียนsizeof(referenceVariable)มันจะให้ขนาดของวัตถุที่อ้างอิงโดยreferenceVariableไม่ใช่ของตัวอ้างอิงเอง มันไม่มีขนาดของมันเองซึ่งเป็นสาเหตุที่คอมไพเลอร์ไม่สามารถคำนวณขนาดที่อาร์เรย์ต้องการได้


3
ถ้าเช่นนั้นคอมไพเลอร์สามารถคำนวณขนาดของโครงสร้างที่มีเพียงการอ้างอิงได้อย่างไร
Juster

คอมไพเลอร์ทราบขนาดทางกายภาพของการอ้างอิงซึ่งเป็นขนาดเดียวกับตัวชี้ ในความเป็นจริงการอ้างอิงเป็นพอยน์เตอร์ชี้ให้เห็นความหมายทางความหมาย ความแตกต่างระหว่างพอยน์เตอร์และการอ้างอิงคือการอ้างอิงมีกฎความหมายค่อนข้างน้อยที่วางไว้เพื่อลดจำนวนข้อบกพร่องที่คุณอาจสร้างขึ้นเมื่อเปรียบเทียบกับพอยน์เตอร์
Kristupas A.

2

เมื่อคุณเก็บบางอย่างในอาเรย์จะต้องรู้ขนาดของมัน ตามมาตรฐาน C ++ มันไม่ได้ระบุว่าการอ้างอิงนั้นต้องการหน่วยเก็บข้อมูลหรือไม่เนื่องจากการสร้างดัชนีผลลัพธ์จะไม่สามารถทำได้


1
แต่โดยการใส่การอ้างอิงดังกล่าวในstruct, ทุกอย่างจะกลายเป็นที่ระบุไว้อย่างชัดเจนกำหนดไว้ดีรับประกันและขนาดที่กำหนด ทำไมจึงมีความแตกต่างอย่างสิ้นเชิงโดยสิ้นเชิงกับสิ่งนี้?
underscore_d

... แน่นอนถ้าใครเริ่มคิดเกี่ยวกับสิ่งที่ห่อหุ้มstructคำตอบที่ดีที่สุดบางอย่างเริ่มแนะนำตัวเอง - แต่สำหรับฉันยังไม่มีใครทำเช่นนั้นแม้จะเป็นหนึ่งในความท้าทายทันทีสำหรับทุกคน หาเหตุผลว่าทำไมคุณไม่สามารถใช้การอ้างอิงที่ยังไม่ได้เปิด
underscore_d

2

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


พิจารณาโค้ดด้านล่างจากคำถามเดิม: int a = 1, b = 2, c = 3; int & arr [] = {a, b, c, 8}; มีความเป็นไปได้น้อยมากที่ a, b, c จะอยู่ในตำแหน่งหน่วยความจำต่อเนื่อง
Amit Kumar

ที่อยู่ไกลจากปัญหาหลักกับแนวคิดของการถือการอ้างอิงในคอนเทนเนอร์
underscore_d

0

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

การอ้างอิงคล้ายคลึงกับนามแฝง ถ้าคุณต้องประกาศอาร์เรย์ของการอ้างอิงคุณจะต้องบอกคอมพิวเตอร์ว่า "จัดสรรความทรงจำหยดนี้ที่ประกอบด้วยรายการต่าง ๆ เหล่านี้กระจัดกระจาย"


1
เหตุใดการทำให้structสมาชิกที่มีสมาชิกเพียงคนเดียวส่งผลให้เกิดการอ้างอิงในสิ่งที่ถูกต้องตามกฎหมายคาดเดาได้และไม่ใช่อสัณฐาน? เหตุใดผู้ใช้จึงต้องปิดการอ้างอิงเพื่อให้สามารถใช้อาเรย์ที่มีความสามารถได้อย่างน่าอัศจรรย์หรือเป็นเพียงข้อ จำกัด เทียม IMO ไม่มีคำตอบได้โดยตรง ฉันถือว่าการโต้แย้งคือ 'วัตถุห่อหุ้มทำให้แน่ใจว่าคุณสามารถใช้ความหมายของค่าในรูปแบบของวัตถุห่อดังนั้นจึงมั่นใจได้ว่าคุณจะได้รับการรับรองคุณค่าซึ่งมีความจำเป็นเพราะเช่นจะทำให้มีความสับสนระหว่างองค์ประกอบและที่อยู่ผู้ตัดสินอย่างไร' ... นั่นคือสิ่งที่คุณหมายถึง?
underscore_d

-2

จริงๆแล้วนี่คือการผสมผสานของไวยากรณ์ C และ C ++

คุณควรอย่างใดอย่างหนึ่งใช้อาร์เรย์ C บริสุทธิ์ซึ่งไม่สามารถอ้างอิงตั้งแต่อ้างอิงเป็นส่วนหนึ่งของภาษา C ++ เท่านั้น หรือคุณใช้วิธี C ++ และใช้std::vectorหรือstd::arrayclass เพื่อจุดประสงค์ของคุณ

ในฐานะที่เป็นส่วนหนึ่งของการแก้ไข: แม้ว่าจะstructเป็นองค์ประกอบจาก C, คุณกำหนดตัวสร้างฟังก์ชั่นและผู้ประกอบการซึ่งทำให้มันเป็น classC ดังนั้นคุณstructจะไม่รวบรวมใน C บริสุทธิ์!


ประเด็นของคุณคืออะไร? std::vectorหรือstd::arrayไม่สามารถมีการอ้างอิงได้ มาตรฐาน C ++ ค่อนข้างชัดเจนว่าไม่มีคอนเทนเนอร์
underscore_d
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.