2010-10-20 20 views
7

tôi cần phải xác định một mẫu cấu trúc như vậy:Loại quyết định dựa trên sự tồn tại của lồng nhau typedef

element<T>::type 

là loại:

T::element_type 

nếu T chứa một (công cộng) typedef tên ELEMENT_TYPE, khác (nếu nó không chứa typedef như vậy)

element<T>::type 

là loại

T::value_type 

nếu T là có thể thay đổi và các loại

const T::value_type 

nếu T là hằng số.

Tôi thực sự đấu tranh với điều này, mọi đề xuất đều được đánh giá cao! :)

Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn trước!

+0

Đối với phần đầu tiên, bạn có thể đọc về SFINAE (google nó) và bạn đang bị ràng buộc để tìm ví dụ minh họa chỉ là những gì bạn cần –

+2

Các bài viết wikipedia trên SFINAE thực sự bao gồm một ví dụ về việc kiểm tra một typedef, được viết bởi bạn thực sự. : P – GManNickG

+0

Không có cách nào để phát hiện rằng typedef, nếu nó tồn tại, là công khai. Tiêu chuẩn này đặc biệt cấm SFINAE làm việc với vi phạm điều kiện truy cập. – Potatoswatter

Trả lời

4

Có lẽ cái gì đó như:

template <typename T> 
struct has_element_type 
{ 
    typedef char yes[1]; 
    typedef char no[2]; 

    template <typename C> 
    static yes& test(typename C::element_type*); 

    template <typename> 
    static no& test(...); 

    static const bool value = sizeof(test<T>(0)) == sizeof(yes); 
}; 

template <typename T> 
struct is_const 
{ 
    static const bool value = false; 
}; 


template <typename T> 
struct is_const<const T> 
{ 
    static const bool value = true; 
}; 

template <typename, bool> // true -> const 
struct value_type_switch; 

template <typename T> 
struct value_type_switch<T, true> 
{ 
    typedef const typename T::value_type type; 
}; 

template <typename T> 
struct value_type_switch<T, false> 
{ 
    typedef typename T::value_type type; 
}; 

template <typename, bool> // true -> has element_type 
struct element_type_switch; 

template <typename T> 
struct element_type_switch<T, true> 
{ 
    typedef typename T::element_type type; 
}; 


template <typename T> 
struct element_type_switch<T, false> 
{ 
    typedef typename value_type_switch<T, is_const<T>::value>::type type; 
}; 

template <typename T> 
struct element 
{ 
    typedef typename element_type_switch<T, 
            has_element_type<T>::value>::type type; 
}; 

này nên dĩ nhiên được tách ra và tổ chức.

+0

trong cấu trúc phần tử không nên là 'typedef typename element_type_switch :: value> :: type type;' thay vì 'typedef typename element_type_switch :: value> type;'? giống nhau trong element_type_switch ... –

+0

@Armen: Ya, typo. Cảm ơn. – GManNickG

+0

Tôi đã thử nghiệm nó và nó hoạt động! Cảm ơn nhiều. Tôi có một sở thích nhỏ cho giải pháp được đề xuất bởi Potatoswapper (ngắn gọn hơn và * với tôi * dễ hiểu hơn), nhưng tôi gặp khó khăn để biên dịch ... Cảm ơn tất cả, quá tệ Tôi không thể chỉ định câu trả lời cho cả hai bởi vì bạn sẽ xứng đáng với nó! :) – stepelu

1

Để thay thế cho việc khai báo một lớp đặc điểm sử dụng SFINAE, bạn có thể sử dụng nó một cách tinh tế hơn với chuyên môn từng phần.

template< typename T > 
struct empty { // support class is like stripped-down enable_if 
    typedef void type; 
}; 

template< class T, typename v = void > // v is always void! 
struct element { 
    typedef typename T::value_type type; 
}; 

template< class T, typename v > 
struct element< T const, v > { 
    typedef typename T::value_type const type; 
}; 

template< class T > // T in deduced context, T::element_type is SFINAE: 
struct element< T, typename empty< typename T::element_type >::type > { 
    typedef typename T::element_type type; 
}; 

... bạn có thể muốn thêm một trường hợp khác để làm cho element_type const cho const T? Thật không may điều này không làm việc trong GCC, mặc dù Comeau chấp nhận nó.

template< class T > 
struct element< T const, typename empty< typename T::element_type >::type > { 
    typedef typename T::element_type const type; 
}; 

Mã tôi sử dụng để kiểm tra điều này:

struct has_et { 
    typedef int element_type; 
}; 

struct has_vt { 
    typedef char value_type; 
}; 

char c; 
int i; 

element<has_vt>::type *cp = &c; 
element<has_et>::type *ip = &i; 
+0

Đối với những người quan tâm đến lỗi, http://gcc.gnu.org/bugzilla/show_bug.cgi?id = 46105 – Potatoswatter

+0

Tôi đã thử (với VS2010) nhưng tôi có vấn đề: nó hoạt động hoàn hảo cho phần tử , phần tử và phần tử , nhưng phần tử không biên dịch (có và không có chuyên môn bổ sung cuối cùng) phàn nàn về sau đó 1 chuyên môn hóa một phần phù hợp. Tôi muốn phần tử :: type là has_et :: element_type. Cảm ơn bạn một lần nữa vì sự giúp đỡ của bạn, rất được đánh giá cao! Bạn có nghĩ rằng vấn đề này có thể được giải quyết? – stepelu

+0

@KRao: Hmm, tôi đã thử sử dụng nó và tôi không thể nhận GCC hoặc Comeau chấp nhận 'const has_et' như một đối số. Đoán tôi nên đã thử nghiệm tốt hơn: vP. Thật vậy, chuyên môn "bổ sung" là cần thiết cho tính chính xác, nhưng theo như tôi có thể nói nó nên hoạt động đúng cách miễn là bạn bao gồm nó. (Bạn có thể xóa 'const' trong typedef của nó, hoặc lấy nó từ chuyên môn không phải const, nhưng nó phải tồn tại.) Có lẽ tôi nên đặt đoạn mã này vào một câu hỏi SO mới, vì tôi chắc chắn nó đúng ... Trong khi chờ đợi, tôi nghĩ giải pháp của GMan là sự lựa chọn an toàn. – Potatoswatter

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