Std :: decay là gì và khi nào nên sử dụng?


184

Những lý do cho sự tồn tại của là std::decaygì? Trong tình huống nào là std::decayhữu ích?


3
Nó được sử dụng trong thư viện chuẩn, ví dụ như khi truyền đối số cho một luồng. Những thứ đó cần được lưu trữ , theo giá trị, vì vậy bạn không thể lưu trữ, ví dụ như mảng. Thay vào đó, một con trỏ được lưu trữ và như vậy. Nó cũng là một siêu dữ liệu bắt chước các điều chỉnh loại tham số chức năng.
dyp

3
decay_t<decltype(...)>là một sự kết hợp tốt đẹp, để xem những gì autosẽ suy luận.
Marc Glisse

58
Biến phóng xạ? :)
saiarcot895

7
std :: decay () có thể làm ba việc. 1 Nó có thể chuyển đổi một mảng T thành T *; 2. Nó có thể loại bỏ vòng loại cv và tham chiếu; 3. Nó chuyển đổi chức năng T thành T *. ví dụ: phân rã (void (char)) -> void (*) (char). Có vẻ như không ai đề cập đến cách sử dụng thứ ba trong các câu trả lời.
r0ng

1
Cảm ơn trời, chúng tôi chưa có quark trong c ++
Wormer

Câu trả lời:


190

<đùa> Rõ ràng nó được sử dụng để phân rã các std::atomicloại phóng xạ thành các loại không phóng xạ. </ đùa>

N2609 là giấy đề xuất std::decay. Bài viết giải thích:

Nói một cách đơn giản, decay<T>::typelà phép biến đổi kiểu nhận dạng trừ khi T là kiểu mảng hoặc tham chiếu đến kiểu hàm. Trong những trường hợp đó decay<T>::type, tương ứng mang lại một con trỏ hoặc một con trỏ tới một hàm.

Ví dụ tạo động lực là 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); 
}

đã chấp nhận các tham số của nó theo giá trị để làm cho chuỗi ký tự hoạt động:

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

Nếu nó chấp nhận tham số của nó bằng tham chiếu, thì T1sẽ được suy ra dưới dạng kiểu mảng, và sau đó xây dựng mộtpair<T1, T2> sẽ không được định dạng.

Nhưng rõ ràng điều này dẫn đến sự thiếu hiệu quả đáng kể. Do đó, cần phải decayáp dụng tập hợp các phép biến đổi xảy ra khi giá trị truyền qua xảy ra, cho phép bạn có được hiệu quả của việc lấy tham số theo tham chiếu, nhưng vẫn có được các phép biến đổi loại cần thiết để mã của bạn hoạt động với chuỗi ký tự, kiểu mảng, kiểu hàm và tương tự:

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)); 
}

Lưu ý: đây không phải là make_pairtriển khai C ++ 11 thực tế - C ++ 11 make_paircũng mở khóa std::reference_wrappers.


"T1 sẽ được suy luận dưới dạng kiểu mảng và sau đó xây dựng một cặp <T1, T2> sẽ không được định dạng." vấn đề ở đây là gì?
camino

6
Tôi hiểu rồi, bằng cách này, chúng tôi sẽ có được cặp <char [4], int> chỉ có thể chấp nhận chuỗi có 4 ký tự
camino

@camino Tôi không hiểu, bạn có nói rằng nếu không có std :: decay thì phần đầu tiên của cặp sẽ chiếm 4 byte cho bốn ký tự thay vì một con trỏ thành char? Đó có phải là những gì std :: về phía trước không? Dừng nó từ phân rã từ một mảng sang một con trỏ?
Zebrafish

3
@Zebrafish Đó là phân rã mảng. Ví dụ: mẫu <tên chữ T> void f (T &); f ("abc"); T là char (&) [4], nhưng mẫu <tên chữ T> void f (T); f ("abc"); T là char *; Bạn cũng có thể tìm thấy lời giải thích tại đây: stackoverflow.com/questions/7797839/ từ
camino

67

Khi xử lý các hàm mẫu lấy tham số của loại mẫu, bạn thường có các tham số phổ quát. Các tham số phổ quát hầu như luôn luôn là các tham chiếu của loại này hay loại khác. Họ cũng có thể dễ bay hơi đủ điều kiện. Như vậy, hầu hết các đặc điểm loại không hoạt động trên chúng như bạn mong đợi:

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-crooking.com/a/24476e60bd906bed

Giải pháp ở đây là sử dụng 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-crooking.com/a/8cbd0119a28a18bd


14
Tôi không hài lòng với điều này. decaylà rất tích cực, ví dụ nếu được áp dụng cho một tham chiếu đến mảng, nó mang lại một con trỏ. Nó thường quá tích cực đối với loại IMHO siêu lập trình này.
dyp

@dyp, cái gì bớt "hung hăng" rồi? Các lựa chọn thay thế là gì?
Serge Rogatch

5
@SergeRogatch Trong trường hợp "tham số phổ quát" / tham chiếu phổ biến / tham chiếu chuyển tiếp, tôi chỉ remove_const_t< remove_reference_t<T> >, có thể được gói trong một siêu dữ liệu tùy chỉnh.
dyp

1
param đang được sử dụng ở đâu? Đó là một đối số của func nhưng tôi không thấy nó được sử dụng ở bất cứ đâu
savram

2
@savram: Trong các đoạn mã này: không phải vậy. Chúng tôi chỉ kiểm tra loại, không phải giá trị. Mọi thứ sẽ hoạt động tốt nếu không tốt hơn nếu chúng ta xóa tên của tham số.
Vịt Mooing
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.