ควรใช้ typedef เมื่อใด


14

ฉันสับสนเล็กน้อยเกี่ยวกับว่าและเมื่อไรฉันควรใช้ typedef ใน C ++ ฉันรู้สึกว่าเป็นการสร้างสมดุลระหว่างการอ่านและความชัดเจน

นี่คือตัวอย่างโค้ดโดยไม่มีการพิมพ์ใด ๆ :

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    static std::map<std::tuple<std::vector<int>::const_iterator,
                               std::vector<int>::const_iterator>,
                    int> lookup_table;

    std::map<std::tuple<std::vector<int>::const_iterator,
                        std::vector<int>::const_iterator>, int>::iterator lookup_it =
        lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

IMO ที่น่าเกลียดทีเดียว ดังนั้นฉันจะเพิ่ม typedefs ภายในฟังก์ชันเพื่อให้ดูดีขึ้น:

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    typedef std::tuple<std::vector<int>::const_iterator,
                       std::vector<int>::const_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

รหัสนี้ยังค่อนข้างงุ่มง่าม แต่ฉันกำจัดเนื้อหาฝันร้ายส่วนใหญ่ แต่ยังคงมีตัววนซ้ำ int เวกเตอร์ตัวแปรนี้กำจัดสิ่งเหล่านี้:

typedef std::vector<int>::const_iterator Input_iterator;

int sum(Input_iterator first, Input_iterator last)
{
    typedef std::tuple<Input_iterator, Input_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

มันดูสะอาด แต่ก็ยังอ่านได้อยู่เหรอ?

เมื่อใดที่ฉันควรใช้ typedef ทันทีที่ฉันมีฝันร้าย ทันทีที่มันเกิดขึ้นมากกว่าหนึ่งครั้ง? ฉันควรจะวางไว้ที่ไหน ฉันควรจะใช้มันในฟังก์ชั่นลายเซ็นหรือเก็บไว้เพื่อการใช้


1
ไม่ซ้ำกัน แต่ค่อนข้างเกี่ยวข้องกับคำถามของฉันprogrammers.stackexchange.com/questions/130679/…
c0da

typedef Input_iterator std::vector<int>::const_iterator;ย้อนกลับ
ต่อ Johansson

1
มีความแตกต่างระหว่างการอ่านและความชัดเจนหรือไม่
Neil

เมื่อ#defineไม่ดีพอ
Thomas Eding

คำตอบ:


6

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

ฉันยังคงชอบตัวอย่างที่สามของคุณดีที่สุด แต่คุณอาจต้องการนึกถึงชื่อและให้ชื่อตัววนซ้ำซึ่งบอกถึงเจตนาของคอนเทนเนอร์

อีกตัวเลือกหนึ่งคือการสร้างแม่แบบจากฟังก์ชันของคุณเพื่อให้สามารถทำงานกับคอนเทนเนอร์อื่นได้เช่นกัน ตามแนวของ

template <typename Input_iterator> ... sum(Input_iterator first, Input_iterator last) 

ซึ่งก็เป็นอย่างมากในจิตวิญญาณของ STL


2

คิดว่า a typedefเป็นการประกาศตัวแปรที่เทียบเท่ากับฟังก์ชั่น: มันทำให้คุณ ...

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

โดยส่วนตัวแล้วฉันฉุนเฉียวถ้าต้องอ่านชื่อแบบยาว ๆ อย่างstd::vector<int>::const_iteratorซ้ำ ๆ

ตัวอย่างที่สามของคุณไม่ซ้ำซากจำเจและอ่านง่ายที่สุด


1

typedefการประกาศใช้เพื่อจุดประสงค์เดียวกับการห่อหุ้ม ด้วยเหตุผลดังกล่าวพวกเขามักจะเหมาะสมที่สุดในไฟล์ส่วนหัวตามหลักการตั้งชื่อเดียวกับคลาสของคุณเนื่องจาก:

  • หากคุณต้องการtypedefโอกาสผู้โทรก็จะได้รับเช่นกันโดยเฉพาะอย่างยิ่งในตัวอย่างของคุณที่จะใช้ในการโต้แย้ง
  • หากคุณต้องการเปลี่ยนประเภทด้วยเหตุผลใดก็ตามรวมถึงการแทนที่ด้วยชั้นเรียนของคุณเองคุณจะต้องทำในที่เดียวเท่านั้น
  • มันทำให้คุณมีแนวโน้มที่จะเกิดข้อผิดพลาดน้อยลงเนื่องจากการเขียนประเภทที่ซับซ้อนซ้ำ ๆ
  • มันซ่อนรายละเอียดการใช้งานที่ไม่จำเป็น

นอกเหนือจากนี้รหัสช่วยจำของคุณจะสะอาดกว่านี้ถ้าคุณแยกมันออกไปเช่น:

if (lookup_table.exists(first, last))
    return lookup_table.get(first, last);

คำแนะนำของคุณอาจดูสะอาดกว่า แต่เสียเวลาโดยทำการค้นหาสองครั้ง
Derek Ledbetter

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