2013-06-12 48 views
10

Tôi nghĩ về quá tải std::is_pointer trong C++ 11 để có được giá trị đúng cho std::shared_ptr<T>, vì sau này hoạt động rất nhiều như là T*.C++ 11: mở rộng std :: is_pointer thành std :: shared_ptr

#include <type_traits> 

namespace std { 

template <typename T> struct is_pointer<shared_ptr<T>> : std::true_type {}; 
template <typename T> struct is_pointer<shared_ptr<T const>> : std::true_type {}; 

} 

Tôi tự hỏi tại sao quá tải này chưa được đưa vào triển khai chuẩn. Có một cạm bẫy mà tôi nhìn?

Là một thay thế, tất nhiên có thể giới thiệu một đặc điểm mới is_shared_ptr<T>.

Thực ra, tôi đã thử đoạn code sau ở nơi đầu tiên:

template <typename T> 
struct is_pointer<shared_ptr<typename std::remove_cv<T>::type>> 
    : std::true_type 
{}; 

mà không biên dịch với GCC 4.7 do

error: template parameters not used in partial specialization: 
error:   ‘T’ 
+3

'is_pointer' là hữu ích trong lập trình mẫu khi tôi muốn biết nếu một cái gì đó là một loại con trỏ thô, không giống như một con trỏ. Bạn có thể thực hiện một 'is_like_ptr' làm những việc như kiểm tra với SFINAE nếu' * p' và '++ p' là các biểu thức hợp lệ. – aschepler

+3

@aschepler: Con trỏ thông minh thường không hỗ trợ số học. 'is_dereferencable', chỉ cần kiểm tra' * p', có thể phù hợp hơn. –

+0

Điểm tốt. Tôi không nghĩ rằng tôi đang tỉnh táo. – aschepler

Trả lời

10

std::is_pointer bằng cách nào đó xuất phát từ Boost và được ban đầu có nghĩa là để phát hiện con trỏ liệu và chức năng gợi ý mà thôi, đây là phía dưới lưu ý bạn có thể tìm thấy trong Boost documentation:

is_pointer phát hiện "thực" kiểu con trỏ chỉ, và không con trỏ thông minh. Người dùng không nên chuyên is_pointer cho các kiểu con trỏ thông minh, vì làm như vậy có thể làm cho mã Boost (và bên thứ ba) không hoạt động chính xác. Người dùng muốn có một đặc điểm để phát hiện con trỏ thông minh nên tạo riêng của họ. Tuy nhiên, lưu ý rằng không có cách nào nói chung để tự động phát hiện các loại con trỏ thông minh một cách tự động, vì vậy một đặc điểm như vậy sẽ phải là một phần chuyên biệt cho từng loại con trỏ thông minh được hỗ trợ.

Chúng có thể chỉ hoạt động như vậy trong thư viện chuẩn để tương thích để giữ mức độ ngạc nhiên thấp cho người dùng đã sử dụng nó. Dù sao, như bạn vừa chứng minh nó, nó rất dễ dàng để tạo ra đặc điểm của riêng bạn để phát hiện con trỏ thông minh. Về cơ bản, những gì bạn đang tìm kiếm sẽ là một đặc điểm sẽ tìm kiếm các loại thực hiện các khái niệm Dereferenceable (mặc dù điều này cũng sẽ làm việc cho std::optional và không chỉ con trỏ/con trỏ thông minh).

Và vì mục đích hoàn chỉnh, thiết kế của is_pointer của Boost có ở đó để chỉ phát hiện con trỏ thô và không phải là các lớp giống con trỏ. Nhưng các câu trả lời khác nên đã cung cấp cho bạn một số thông tin khá tốt về điều đó.

+3

Tôi nghĩ khái niệm' Dereferencable' là thích hợp hơn, vì con trỏ thông minh không tăng, giảm và tất cả những thứ khác đủ điều kiện cho trình vòng lặp truy cập ngẫu nhiên. –

+0

@ArneMertz Cố định, cảm ơn :) – Morwenn

+0

Tôi sẽ không nói nó chỉ dành cho * tăng khả năng tương thích, nhưng do thiết kế vốn có của tất cả các định danh danh mục loại cấp ngôn ngữ đó. Chúng được thiết kế để xác định loại danh mục thực tế của các biến tương phản với các khái niệm ngữ nghĩa cấp cao hơn. –

4

khi tôi đồng ý rằng các đặc điểm loại tổng quát hơn, như behaves_like_pointer (xin lỗi tên ngu ngốc), is_callable (cho tất cả những thứ có ()) hoặc is_indexable (đối với những thứ giống như mảng) sẽ rất hữu ích, đó chắc chắn không phải là những thứ l ike is_pointer, is_function hoặc is_array đã được thiết kế cho. Chúng là những đặc điểm xác định danh mục loại ngôn ngữ cứng thực tế, giống như is_integral, is_class hoặc is_rvalue_reference.

Vì vậy, quá mức is_pointer cho bất kỳ loại con trỏ thông minh nào sẽ đồng tình với mục đích ban đầu đó và mục đích đó là mục đích rõ ràng và không rõ ràng. Nhưng tôi vẫn đồng ý rằng thêm các danh mục loại khái niệm chung khác như is_smart_pointer, is_callable, is_nothrow_swappable hoặc is_hashable cũng sẽ rất hữu ích.

8

Tôi nghĩ về quá tải std :: is_pointer trong C++ 11 để có được true cho std :: shared_ptr, vì sau này hoạt động rất giống với T *.

Nó không có. Chúc bạn may mắn làm ++p hoặc p[i] với số shared_ptr.

Tôi tự hỏi tại sao quá tải này chưa được bao gồm trong quá trình triển khai chuẩn. Có một cạm bẫy mà tôi nhìn?

Nó không được bao gồm bởi vì nó có thể đã được chỉ đơn giản là sai: is_pointer cho bạn biết nếu một type là một kiểu con trỏ (§3.9.2). shared_ptr không phải là kiểu con trỏ , do đó, có is_pointer<shared_ptr<int>::value là sự thật sẽ đơn giản là sai.

Thực ra, tôi đã thử đoạn code sau ở nơi đầu tiên:

template <typename T> 
struct is_pointer<shared_ptr<typename std::remove_cv<T>::type>> 
    : std::true_type 
{}; 

Chuyện quái gì đang remove_cv làm gì ở đó? Các "công trình" sau đây trong GCC.

template <typename T> 
struct is_pointer<shared_ptr<T>> 
    : std::true_type 
{}; 

Tuy nhiên, nó có hành vi không xác định. Nói chung, bạn không được phép thêm chuyên môn vào các mẫu trong không gian tên std nếu chúng không đồng ý với ngữ nghĩa được xác định. Các ngữ nghĩa cho std::is_pointer<T> sao cho nó chỉ xuất phát từ std::true_type nếu T là loại con trỏ mà không phải là std::shared_ptr. Điều đó một mình sẽ là đủ, nhưng trong trường hợp cụ thể này, tiêu chuẩn thực sự đi theo chiều dài của việc cấm nó một cách rõ ràng (§20.9.2):

Hành vi của một chương trình thêm chuyên môn cho bất kỳ mẫu lớp nào được định nghĩa trong điều này là không xác định trừ khi được quy định khác.

Mẫu duy nhất từ ​​<type_traits> mà người dùng có thể thêm chuyên môn là std::common_type.

+0

+1 Để đề cập đến các mẫu chuyên biệt '' (ngoại trừ 'common_type') là bất hợp pháp. Thật không may, tôi đã nhìn thấy ngay cả lập trình viên giàu kinh nghiệm cho thấy để làm điều này! Obrigado. –

+0

C++ 17 ràng buộc có cấu trúc cũng bây giờ hy vọng người dùng chuyên ''. – user2023370

0

Các câu trả lời khác bao gồm các chi tiết kỹ thuật và một số thông tin cơ bản.

Ý tưởng về type_traits trong std :: là cung cấp nguyên thủy. Bạn sử dụng những người đó ra khỏi hộp và thực hiện chuyên môn chỉ để bao gồm các loại tự xác định của bạn để theo dõi nhận báo cáo chính xác cho ngữ nghĩa gốc.

Điều bạn muốn thực sự (IMO) không chuyển hướng mẫu is_pointer, nhưng để có chức năng truy vấn bí mật ngữ nghĩa của bạn. Vì vậy, đó là những gì bạn nên làm: của riêng bạn is_maybesmart_pointer <> mà báo cáo đúng cho con trỏ ban đầu và bất cứ điều gì khác mà bạn mong muốn. Và sử dụng điều đó trong mã của bạn.

Tinh chỉnh bản gốc theo ý tưởng ban đầu sẽ hoàn toàn có thể dẫn đến vi phạm ODR như cách bạn biết liên kết libs mà bạn chưa sử dụng is_pointer với shared_ptr hoặc cái gì đó?

Các vấn đề liên quan