ฉันควรใช้การลดชนิดการส่งคืนอัตโนมัติ C ++ 14 เมื่อใด


144

ด้วยการเปิดตัว GCC 4.8.0 เรามีคอมไพเลอร์ที่รองรับการหักค่าส่งคืนชนิดอัตโนมัติซึ่งเป็นส่วนหนึ่งของ C ++ 14 ด้วย-std=c++1yฉันสามารถทำสิ่งนี้:

auto foo() { //deduced to be int
    return 5;
}

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

สถานการณ์ 1

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

สถานการณ์ที่ 2

สถานการณ์ต่อไปคือการหลีกเลี่ยงประเภทการคืนที่ซับซ้อนมากขึ้น เป็นตัวอย่างที่เบามาก:

template<typename T, typename U>
auto add(T t, U u) { //almost deduced as decltype(t + u): decltype(auto) would
    return t + u;
}

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

สถานการณ์ 3

ถัดไปเพื่อป้องกันความซ้ำซ้อน:

auto foo() {
    std::vector<std::map<std::pair<int, double>, int>> ret;
    //fill ret in with stuff
    return ret;
}

ใน C ++ 11 บางครั้งเราสามารถreturn {5, 6, 7};แทนที่เวกเตอร์ได้ แต่นั่นไม่ได้ผลเสมอไปและเราจำเป็นต้องระบุประเภทในทั้งส่วนหัวของฟังก์ชั่นและส่วนของฟังก์ชั่น นี่คือการซ้ำซ้อนอย่างหมดจดและการลดชนิดการส่งคืนอัตโนมัติช่วยเราจากความซ้ำซ้อนนั้น

สถานการณ์ 4

ในที่สุดมันสามารถใช้แทนฟังก์ชั่นที่ง่ายมาก:

auto position() {
    return pos_;
}

auto area() {
    return length_ * width_;
}

แม้ว่าบางครั้งเราอาจดูที่ฟังก์ชั่นต้องการทราบประเภทที่แน่นอนและหากไม่ได้ระบุไว้เราต้องไปยังจุดอื่นในรหัสเช่นที่pos_แจ้งไว้

ข้อสรุป

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

โปรดทราบว่าคำถามหลายข้อนั้นมีไว้เพื่อช่วยในการค้นหามุมมองที่จะตอบคำถามนี้


18
คำถามยอดเยี่ยม! ในขณะที่คุณกำลังถามซึ่งสถานการณ์ทำให้โค้ด "ดี" ผมยังสงสัยที่สถานการณ์จะทำให้มันแย่ลง
Drew Dormann

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

2
@NicolBolas บางที แต่ความจริงที่ว่าในการเปิดตัวคอมไพเลอร์ตอนนี้จะเพียงพอสำหรับคนที่จะเริ่มใช้มันในรหัสส่วนตัว (แน่นอนว่าต้องถูกหลีกเลี่ยงจากโครงการในตอนนี้) ฉันเป็นหนึ่งในคนเหล่านั้นที่ชอบใช้คุณลักษณะที่เป็นไปได้ใหม่ล่าสุดในรหัสของฉันเองและในขณะที่ฉันไม่รู้ว่าข้อเสนอจะไปกับคณะกรรมการได้ดีแค่ไหน บางสิ่งบางอย่าง มันอาจจะดีกว่าทิ้งไว้เพื่อใช้ในภายหลังหรือ (ฉันไม่รู้ว่ามันจะทำงานได้ดี) ฟื้นฟูเมื่อเรารู้ว่ามันกำลังมา
chris

1
@NicolBolas ถ้ามันช่วยได้มันถูกประกาศใช้ตอนนี้: p
chris

1
คำตอบปัจจุบันไม่ได้พูดถึงว่าการแทนที่->decltype(t+u)ด้วยการหักอัตโนมัติจะฆ่า SFINAE
Marc Glisse

คำตอบ:


62

C ++ 11 ทำให้เกิดคำถามที่คล้ายกัน: เมื่อใดจึงควรใช้การลดชนิดส่งคืนใน lambdas และเมื่อใช้autoตัวแปร

คำตอบดั้งเดิมของคำถามใน C และ C ++ 03 นั้นคือ "ข้ามขอบเขตคำสั่งเราทำให้ประเภทชัดเจนภายในนิพจน์ที่พวกเขามักจะบอกเป็นนัย แต่เราสามารถทำให้พวกเขาชัดเจนกับปลดเปลื้อง" C ++ 11 และ C ++ 1y แนะนำเครื่องมือการหักประเภทเพื่อให้คุณไม่ต้องพิมพ์ในสถานที่ใหม่

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

เนื่องจาก "ความสามารถในการอ่าน" ไม่ได้ถูกกำหนดอย่างเป็นกลาง [*] และยิ่งไปกว่านั้นมันแตกต่างกันไปตามผู้อ่านคุณมีความรับผิดชอบในฐานะผู้แต่ง / บรรณาธิการของโค้ดที่ไม่สามารถพอใจได้โดยไกด์นำเที่ยว แม้ในกรณีที่คู่มือนำสไตล์ระบุบรรทัดฐานคนที่แตกต่างกันจะชอบบรรทัดฐานที่แตกต่างกันและมักจะพบสิ่งที่ไม่คุ้นเคยที่จะ "อ่านง่ายกว่า" ดังนั้นความสามารถในการอ่านของกฎสไตล์เฉพาะที่เสนอจึงสามารถตัดสินได้ในบริบทของกฎสไตล์อื่น ๆ เท่านั้น

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

[*] บางครั้งมีคนพยายามทำการวัดอย่างมีวัตถุประสงค์ ในระดับเล็ก ๆ ที่ทุกคนเคยเจอกับผลลัพธ์ที่มีความสำคัญทางสถิติและโดยทั่วไปแล้วพวกเขาจะถูกเพิกเฉยอย่างสมบูรณ์จากโปรแกรมเมอร์ที่ทำงานเพื่อสนับสนุนสัญชาตญาณของผู้เขียนว่า "อ่าน" ได้อย่างไร


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

1
@ Chris: ฉันพูดว่าฉันคิดว่ามันทั้งหมดลงมาในสิ่งเดียวกัน มันจะดีกว่าสำหรับรหัสของคุณที่จะพูดว่า "ประเภทของสิ่งนี้คือ X" หรือมันจะดีกว่าสำหรับรหัสของคุณที่จะพูดว่า "ประเภทของสิ่งนี้เป็นสิ่งที่ไม่เกี่ยวข้องคอมไพเลอร์จำเป็นต้องรู้ แต่เราไม่จำเป็นต้องพูดว่า " เมื่อเราเขียน1.0 + 27Uเราจะยืนยันหลังเมื่อเราเขียน(double)1.0 + (double)27Uเราจะยืนยันอดีต ความเรียบง่ายของฟังก์ชั่น, ระดับการทำซ้ำ, การหลีกเลี่ยงdecltypeอาจมีส่วนร่วมกับสิ่งนั้น แต่ไม่มีใครจะตัดสินใจได้อย่างน่าเชื่อถือ
Steve Jessop

1
มันจะดีกว่าสำหรับรหัสของคุณที่จะพูดว่า "ประเภทของสิ่งนี้คือ X" หรือมันจะดีกว่าสำหรับรหัสของคุณที่จะพูดว่า "ประเภทของสิ่งนี้เป็นสิ่งที่ไม่เกี่ยวข้องคอมไพเลอร์จำเป็นต้องรู้ แต่เราไม่จำเป็นต้องพูดว่า " - ประโยคนั้นสอดคล้องกับสิ่งที่ฉันค้นหา ฉันจะคำนึงถึงเรื่องนี้เมื่อฉันเจอตัวเลือกในการใช้คุณสมบัตินี้และautoโดยทั่วไป
chris

1
ฉันต้องการเพิ่มว่า IDEs อาจบรรเทา "ปัญหาการอ่าน" ใช้ Visual Studio ตัวอย่างเช่น: หากคุณวางเหนือautoคำหลักคำหลักนั้นจะแสดงประเภทผลตอบแทนจริง
andreee

1
@ andreee: มันเป็นความจริงภายในขอบเขต หากประเภทมีชื่อแทนจำนวนมากดังนั้นการทราบว่าประเภทจริงไม่ใช่สิ่งที่มีประโยชน์อย่างที่คุณคาดหวัง ตัวอย่างเช่นชนิดตัววนซ้ำอาจมีint*แต่สิ่งที่สำคัญจริง ๆ ถ้ามีก็เพราะเหตุผลว่าint*เป็นเพราะสิ่งที่std::vector<int>::iterator_typeมีอยู่ในตัวเลือกการสร้างปัจจุบันของคุณ!
Steve Jessop

30

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

template<typename F, typename Tuple, int... I>
  auto
  apply_(F&& f, Tuple&& args, int_seq<I...>) ->
  decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...))
  {
    return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...);
  }

template<typename F, typename Tuple,
         typename Indices = make_int_seq<std::tuple_size<Tuple>::value>>
  auto
  apply(F&& f, Tuple&& args) ->
  decltype(apply_(std::forward<F>(f), std::forward<Tuple>(args), Indices()))
  {
    return apply_(std::forward<F>(f), std::forward<Tuple>(args), Indices());
  }

ตัวอย่างนี้จะนำมาจากกระดาษคณะกรรมการอย่างเป็นทางการN3493 วัตถุประสงค์ของฟังก์ชันapplyคือการส่งต่อองค์ประกอบของ a std::tupleไปยังฟังก์ชันและส่งคืนผลลัพธ์ int_seqและmake_int_seqเป็นเพียงส่วนหนึ่งของการดำเนินการและอาจจะสร้างความสับสนให้ผู้ใช้ใด ๆ พยายามที่จะเข้าใจสิ่งที่มันไม่

อย่างที่คุณเห็นชนิดการคืนค่านั้นไม่มีอะไรมากกว่าdecltypeนิพจน์ที่ส่งคืน นอกจากนี้ยังapply_ไม่ได้หมายความว่าจะต้องเห็นโดยผู้ใช้ผมไม่แน่ใจว่าประโยชน์ของการจัดเก็บเอกสารประเภทกลับของมันเมื่อมันเป็นมากหรือน้อยเช่นเดียวกับapply'หนึ่ง ฉันคิดว่าในกรณีนี้การวางประเภทส่งคืนทำให้ฟังก์ชั่นอ่านง่ายขึ้น โปรดทราบว่าประเภทผลตอบแทนที่แท้จริงนี้ได้ลดลงและถูกแทนที่ด้วยdecltype(auto)ในข้อเสนอที่จะเพิ่มลงapplyในมาตรฐานN3915 (โปรดทราบว่าคำตอบดั้งเดิมของฉันนำหน้ากระดาษนี้มาก่อน):

template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
    return forward<F>(f)(get<I>(forward<Tuple>(t))...);
}

template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
    using Indices = make_index_sequence<tuple_size<decay_t<Tuple>>::value>;
    return apply_impl(forward<F>(f), forward<Tuple>(t), Indices{});
}

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


อีกสิ่งหนึ่งที่ยังไม่ได้รับการกล่าวถึงอีกในขณะที่declype(t+u)ช่วยให้การใช้การแสดงออก SFINAE , decltype(auto)ไม่ได้ (แม้ว่าจะมีข้อเสนอที่จะเปลี่ยนพฤติกรรมนี้) ยกตัวอย่างfoobarฟังก์ชั่นที่จะเรียกfooฟังก์ชั่นสมาชิกประเภทถ้ามันมีอยู่หรือเรียกbarฟังก์ชั่นสมาชิกประเภทถ้ามันมีอยู่และสมมติว่าชั้นมักจะมีแน่นอนfooหรือbarแต่ทั้งสองอย่างในครั้งเดียว:

struct X
{
    void foo() const { std::cout << "foo\n"; }
};

struct Y
{
    void bar() const { std::cout << "bar\n"; }
};

template<typename C> 
auto foobar(const C& c) -> decltype(c.foo())
{
    return c.foo();
}

template<typename C> 
auto foobar(const C& c) -> decltype(c.bar())
{
    return c.bar();
}

การโทรfoobarหาอินสแตนซ์ของXจะแสดงขึ้นfooในขณะที่โทรfoobarหาอินสแตนซ์ของYจะแสดงbarขึ้น หากคุณใช้การลดชนิดการส่งคืนอัตโนมัติแทน (ไม่decltype(auto)ว่าจะมีหรือไม่มี) คุณจะไม่ได้รับนิพจน์ SFINAE และการเรียกfoobarใช้อินสแตนซ์ของXหรือYจะทำให้เกิดข้อผิดพลาดในการรวบรวม


8

มันไม่จำเป็น เวลาที่คุณควรคุณจะได้รับคำตอบที่แตกต่างกันมากมาย ฉันจะไม่พูดจนกว่าจะได้รับการยอมรับว่าเป็นส่วนหนึ่งของมาตรฐานและได้รับการสนับสนุนอย่างดีจากผู้รวบรวมส่วนใหญ่ในลักษณะเดียวกัน

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


1
ฉันยอมรับว่าผู้ที่มีภูมิหลังแตกต่างกันจะมีความคิดเห็นที่แตกต่างกันในเรื่องนี้ แต่ฉันหวังว่านี่จะเป็นข้อสรุปของซีพลัสพลัส ใน (เกือบ) ทุกกรณีมันไม่สามารถใช้งานได้กับการใช้ภาษาในทางที่ผิดเพื่อพยายามทำให้เป็นภาษาอื่นเช่นการใช้#defines เพื่อเปลี่ยน C ++ เป็น VB คุณสมบัติโดยทั่วไปมีความสอดคล้องที่ดีภายในความคิดของภาษาว่ามีการใช้งานที่เหมาะสมอย่างไรและอะไรไม่เป็นไปตามสิ่งที่โปรแกรมเมอร์ภาษานั้นคุ้นเคย คุณสมบัติเดียวกันนี้อาจมีอยู่ในหลายภาษา แต่แต่ละแห่งมีแนวทางของตนเองในการใช้งาน
คริส

2
คุณสมบัติบางอย่างมีฉันทามติที่ดี หลายคนทำไม่ได้ ฉันรู้โปรแกรมเมอร์จำนวนมากที่คิดว่า Boost ส่วนใหญ่เป็นขยะที่ไม่ควรใช้ ฉันก็รู้ว่าใครบางคนคิดว่ามันเป็นสิ่งที่ยิ่งใหญ่ที่สุดที่จะเกิดขึ้นกับ C ++ ไม่ว่าในกรณีใดฉันคิดว่ามีการพูดคุยที่น่าสนใจเกี่ยวกับเรื่องนี้ แต่เป็นตัวอย่างที่แท้จริงของการปิดตัวเลือกที่ไม่สร้างสรรค์ในเว็บไซต์นี้
Gabe Sechan

2
ไม่ฉันไม่เห็นด้วยกับคุณอย่างสมบูรณ์และฉันคิดว่าautoเป็นพรบริสุทธิ์ มันกำจัดความซ้ำซ้อนจำนวนมาก มันเป็นเพียงความเจ็บปวดที่จะทำซ้ำประเภทผลตอบแทนในบางครั้ง หากคุณต้องการคืนแลมบ์ดาคุณสามารถทำได้โดยไม่ต้องเก็บผลลัพธ์ไว้ใน a std::functionซึ่งอาจทำให้เกิดค่าใช้จ่าย
Yongwei Wu

1
มีอย่างน้อยหนึ่งสถานการณ์ที่ทุกอย่างล้วน แต่จำเป็นทั้งหมด สมมติว่าคุณจำเป็นต้องเรียกใช้ฟังก์ชันจากนั้นบันทึกผลลัพธ์ก่อนส่งคืนและฟังก์ชันไม่จำเป็นต้องมีชนิดส่งคืนเหมือนกันทุกประการ หากคุณทำผ่านฟังก์ชันการบันทึกที่ใช้ฟังก์ชันและอาร์กิวเมนต์เป็นพารามิเตอร์คุณจะต้องประกาศประเภทการคืนค่าของฟังก์ชันการบันทึกautoเพื่อให้ตรงกับประเภทการส่งคืนของฟังก์ชันที่ส่งผ่าน
Justin Time - Reinstate Monica

1
[มีเทคนิคอีกวิธีหนึ่งในการทำเช่นนี้ แต่ใช้มายากลแม่แบบเพื่อทำสิ่งเดียวกันโดยทั่วไปและยังต้องการฟังก์ชันการบันทึกautoสำหรับประเภทการส่งคืนตามมา]
Justin Time - Reinstate Monica

7

มันไม่มีอะไรเกี่ยวข้องกับความเรียบง่ายของฟังก์ชั่น (เหมือนที่ถูกลบไปแล้วตอนนี้ซ้ำกับคำถามนี้)

ประเภทการคืนค่าคงที่ (ไม่ใช้auto) หรือขึ้นอยู่กับวิธีที่ซับซ้อนในพารามิเตอร์เทมเพลต (ใช้autoในกรณีส่วนใหญ่จับคู่กับdecltypeเมื่อมีหลายจุดส่งคืน)


3

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

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

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

ในขณะที่มีวิธีการอื่น ๆ ที่สามารถจัดการได้การใช้autoประเภทการคืนสินค้าดูเหมือนว่าเหมาะสม


1
ในกรณีเหล่านั้นมันจะดีกว่าdecltype(foo())ไหมถ้าจะเขียน?
Oren S

โดยส่วนตัวแล้วฉันรู้สึกว่าtypedefการประกาศและนามแฝง (เช่นusingการประกาศประเภท) นั้นดีกว่าในกรณีเหล่านี้โดยเฉพาะอย่างยิ่งเมื่อมีการกำหนดคลาส
MAChitgarha

3

ฉันต้องการให้ตัวอย่างซึ่งการคืนค่าประเภทอัตโนมัตินั้นสมบูรณ์แบบ:

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

inline auto CreateEntity() { return GetContext()->GetEntityManager()->CreateEntity(); }

PS: ขึ้นอยู่กับนี้คำถาม


2

สำหรับสถานการณ์ที่ 3 ฉันจะเปลี่ยนประเภทการส่งคืนของฟังก์ชันลายเซ็นต์พร้อมตัวแปรโลคอลเพื่อส่งคืน มันจะทำให้มันชัดเจนขึ้นสำหรับลูกค้าโปรแกรมเมอร์หมวกฟังก์ชั่นกลับมา แบบนี้:

สถานการณ์ที่ 3 เพื่อป้องกันความซ้ำซ้อน:

std::vector<std::map<std::pair<int, double>, int>> foo() {
    decltype(foo()) ret;
    return ret;
}

ใช่มันไม่มีคีย์เวิร์ดอัตโนมัติ แต่ตัวการหลักเหมือนกันเพื่อป้องกันความซ้ำซ้อนและให้โปรแกรมเมอร์ที่ไม่สามารถเข้าถึงแหล่งที่มาได้ง่ายขึ้น


2
IMO การแก้ไขที่ดีกว่าสำหรับสิ่งนี้คือการระบุชื่อโดเมนเฉพาะสำหรับแนวคิดของสิ่งที่ตั้งใจให้แสดงเป็น a vector<map<pair<int,double>,int>และจากนั้นใช้
davidbak
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.