std :: ผุคืออะไรและควรใช้เมื่อใด


185

อะไรคือสาเหตุของการมีอยู่ของstd::decay? ในสถานการณ์ใดที่std::decayมีประโยชน์?


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

3
decay_t<decltype(...)>เป็นการผสมผสานที่ดีเพื่อดูว่าอะไรautoจะอนุมาน
Marc Glisse

58
ตัวแปรกัมมันตภาพรังสี? :)
saiarcot895

7
std :: decay () สามารถทำสามสิ่งได้ 1 มันสามารถแปลงอาเรย์ของ T เป็น T *; 2. มันสามารถลบรอบคัดเลือกและอ้างอิง; 3. มันจะแปลงฟังก์ชัน T เป็น T * เช่นการสลายตัว (เป็นโมฆะ (ถ่าน)) -> เป็นโมฆะ (*) (ถ่าน) ดูเหมือนไม่มีใครพูดถึงการใช้งานครั้งที่สามในคำตอบ
r0ng

1
ขอบคุณพระเจ้าที่เรายังไม่มีควาร์กใน c ++ ยัง
Wormer

คำตอบ:


192

<โจ๊ก> เห็นได้ชัดว่ามันใช้เพื่อสลายstd::atomicประเภทกัมมันตภาพรังสีให้กลายเป็นประเภทที่ไม่มีกัมมันตภาพรังสี </joke>

N2609std::decayเป็นกระดาษที่นำเสนอ กระดาษอธิบาย:

พูดง่ายๆdecay<T>::typeคือการแปลงชนิดข้อมูลเฉพาะตัวยกเว้นว่า T เป็นประเภทอาร์เรย์หรือการอ้างอิงถึงประเภทฟังก์ชัน ในกรณีเหล่านั้นdecay<T>::typeให้ตัวชี้หรือตัวชี้ไปยังฟังก์ชั่นตามลำดับ

ตัวอย่างแรงจูงใจคือ C ++ 03 std::make_pair:

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

ซึ่งยอมรับพารามิเตอร์ด้วยค่าเพื่อให้ตัวอักษรสตริงทำงาน:

std::pair<std::string, int> p = make_pair("foo", 0);

ถ้ามันยอมรับพารามิเตอร์โดยอ้างอิงแล้วT1จะถูกหักเป็นประเภทอาร์เรย์และจากนั้นการสร้างpair<T1, T2>จะเป็นรูปแบบที่ไม่ดี

แต่เห็นได้ชัดว่าสิ่งนี้นำไปสู่การไร้ประสิทธิภาพที่สำคัญ ดังนั้นความจำเป็นในdecayการใช้ชุดการแปลงที่เกิดขึ้นเมื่อค่า pass-by-value เกิดขึ้นช่วยให้คุณได้รับประสิทธิภาพของการอ้างอิงพารามิเตอร์ แต่ยังได้รับการแปลงชนิดที่จำเป็นสำหรับรหัสของคุณเพื่อทำงานกับตัวอักษรสตริง ประเภทอาร์เรย์ประเภทฟังก์ชั่นและสิ่งที่ชอบ:

template <class T1, class T2> 
inline pair< typename decay<T1>::type, typename decay<T2>::type > 
make_pair(T1&& x, T2&& y)
{ 
    return pair< typename decay<T1>::type, 
                 typename decay<T2>::type >(std::forward<T1>(x), 
                                            std::forward<T2>(y)); 
}

หมายเหตุ:นี่ไม่ใช่การนำ C ++ 11 make_pairไปใช้จริง - C ++ 11 make_pairยังไม่std::reference_wrapperได้แยกออก


"T1 จะถูกอนุมานว่าเป็นประเภทอาเรย์แล้วการสร้างคู่ <T1, T2> จะไม่เกิดขึ้น" ปัญหานี่คืออะไร
camino

6
ฉันเข้าใจแล้วด้วยวิธีนี้เราจะได้คู่ <char [4], int> ซึ่งสามารถรับสายได้เพียง 4 ตัวอักษร
camino

@ คามิโนฉันไม่เข้าใจคุณกำลังบอกว่าหากไม่มี std :: decay ส่วนแรกของคู่จะมีขนาด 4 ไบต์สำหรับสี่ตัวอักษรแทนที่จะเป็นตัวชี้เดียว นั่นคือสิ่งที่มาตรฐาน :: ไปข้างหน้าไม่? หยุดมันจากการเน่าเปื่อยจากอาร์เรย์ไปยังตัวชี้หรือไม่?
Zebrafish

3
@ Zebrafish มันคือการสลายตัวของอาร์เรย์ ตัวอย่างเช่น: เทมเพลต <typename T> void f (T &); f ( "เอบีซี"); T คือ char (&) [4] แต่แม่แบบ <typename T> เป็นโมฆะ f (T); f ( "เอบีซี"); T เป็นถ่าน *; คุณยังสามารถหาคำอธิบายได้ที่นี่: stackoverflow.com/questions/7797839/…
camino

69

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

template<class T>
void func(T&& param) {
    if (std::is_same<T,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

int main() {
    int three = 3;
    func(three);  //prints "param is not an int"!!!!
}

http://coliru.stacked-crooked.com/a/24476e60bd906bed

ทางออกที่นี่คือการใช้std::decay:

template<class T>
void func(T&& param) {
    if (std::is_same<typename std::decay<T>::type,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd


14
ฉันไม่พอใจกับสิ่งนี้ decayมีความก้าวร้าวมากเช่นถ้านำไปใช้กับการอ้างอิงถึงอาร์เรย์จะให้ตัวชี้ โดยทั่วไปแล้วจะมีความก้าวร้าวเกินกว่าที่ IMHO ประเภทนี้จะใช้ในการเปรียบเทียบ
dyp

@dyp "ก้าวร้าว" ในตอนนั้นคืออะไร ทางเลือกอื่นคืออะไร?
Serge Rogatch

5
@SergeRogatch ในกรณีของ "พารามิเตอร์สากล" / การอ้างอิงสากล / การอ้างอิงการส่งต่อฉันremove_const_t< remove_reference_t<T> >จะห่อด้วยเมตาฟังก์ชั่นที่กำหนดเอง
dy

1
Param ใช้ที่ไหน? มันเป็นข้อโต้แย้งของ func แต่ฉันไม่เห็นว่ามันถูกใช้ที่ใดก็ได้
savram

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