2012-11-24 32 views
5

Tôi xin lỗi điều này nghe có vẻ giống như một câu hỏi phổ biến, tôi không thể tìm thấy câu trả lời cho vấn đề của mình như tôi thấy. Bài đăng gần nhất sẽ là bài đăng này: Template Specialization for basic POD onlyLoại xung đột trong quá tải nhà điều hành mẫu

Giả sử tôi có một lớp template <class T> class A {...}; và tôi muốn quá tải toán tử + làm toán tử nhị phân nội bộ (hai đối tượng loại A) và làm toán tử hỗn hợp A và số POD loại).

Lý tưởng nhất, những gì tôi muốn viết là:

#include <type_traits> 
using namespace std; 

// Declare/fine template 
template <class T> class A {...}; 

// Internal binary operator 
template < class T, class U > 
    A< typename common_type<T,U>::type > 
operator+ (const A<T> &a, const A<U> &a) { ... } 

// Mixed binary operator 
template < class T, class U > 
    A< typename common_type<T,U>::type > 
operator+ (const A<T> &a, const U &b) { ... } 

Nhưng sau đó nó có vẻ như định nghĩa thứ hai là mâu thuẫn với cái đầu tiên. Sử dụng định nghĩa thứ hai, tôi biết làm thế nào để đảm bảo U là một loại POD số, ​​đó không phải là vấn đề. Nếu tôi đi theo cách đó, vấn đề là tôi không có cách nào để biết loại mẫu cơ bản nào được bao bọc trong U nếu đó là một số A.

Hãy cho tôi biết nếu câu hỏi của tôi không rõ ràng và cảm ơn trước! :)

EDIT: Các đặc điểm kỹ thuật mẫu đã bị xóa bởi bộ lọc HTML, trong câu cuối cùng của tôi "U nếu nó là một số A<T>". Tóm lại, tôi nói T bị ẩn.

+0

'template , U> :: giá trị, khoảng trống> :: type> A :: type> toán tử + (const A & a, const U &b); 'nên thực hiện thủ thuật. – Morwenn

+0

Ý bạn là gì bởi" kiểu mẫu cơ sở được bao bọc trong U "? Nhà điều hành hỗn hợp sẽ không được chọn nếu U là' A 'vì nội bộ là Bạn có muốn đối xử với vụ án 'A < A>' trong toán tử nội bộ không? – pmr

+0

Cảm ơn tất cả vì sự giúp đỡ của bạn. Bạn đã đúng, vấn đề thực sự xảy ra trước đây, vì common_type. nhập giữa 'A ' và U, chúng tôi là bort trước khi trận đấu tốt nhất có thể được đánh giá. Morwenn, giải pháp của bạn trông giống như một cái gì đó tôi đã cố gắng, nhưng không chính xác trong bối cảnh này; U có thể là 'A ' với S!= T, và tôi vẫn có thể thực hiện thao tác. – Sheljohn

Trả lời

2

Bạn có thể làm cho nó làm việc với một đặc điểm helper ít để phân biệt chuyên ngành của A từ các loại tổng quát hơn:

#include <type_traits> 


// "A" template  

template <typename> class A {}; 


// Traits for "A-ness": 

template <typename> struct is_a : std::false_type { }; 
template <typename T> struct is_a<A<T>> : std::true_type { }; 


// Operators: 

template <class T, class U> 
A<typename std::common_type<T, U>::type> 
operator+(const A<T> & a, const A<U> & b); 

template <class T, class U, 
      typename = typename std::enable_if<!is_a<U>::value>::type> 
A<typename std::common_type<T, U>::type> 
operator+(const A<T> & a, const U & b); 

này không bao gồm sự quá tải thứ hai từ tập hữu hiệu ngay lập tức, và do đó vấn đề xác định sự trở lại loại quá tải thứ hai không bao giờ xuất hiện khi chỉ có cái đầu tiên được mong muốn.

(Đây là một ví dụ của việc sử dụng enable_if trong lập luận mẫu mặc định để kiểm soát các thiết lập tình trạng quá tải.)

+0

Bạn là một vị cứu tinh cuộc sống :) Tôi mới làm quen với các thủ thuật "lập trình mẫu" này, tôi nghĩ đó chính xác là những gì tôi cần. Hãy để tôi kiểm tra nó và tôi sẽ xác nhận câu trả lời. Cảm ơn một lần nữa! – Sheljohn

+0

Nó hoạt động, cảm ơn rất nhiều! :) – Sheljohn

1

Bạn có thể viết một SFINAE thân thiện common_type - Tôi cá nhân trong trại mà những đặc điểm nên hầu như luôn luôn SFINAE . Để wit:

// Black hole metafunction that eats everything 
template<typename...> struct void_ { using type = void; }; 

template<typename... T> 
using Void = typename void_<T...>::type; 

// Due to std::common_type being variadic we need to 
// pass a variadic pack around 
template<typename... T> struct list {}; 

// Actually defined, but with no member types for SFINAE purposes 
template<typename Sequence, typename Sfinae = void> 
struct common_type_impl {}; 

template<typename... T> 
struct common_type_impl<list<T...>, Void<typename std::common_type<T...>::type>> 
: std::common_type<T...> {}; 

template<typename... T> struct common_type: common_type_impl<list<T...>> {}; 

Bây giờ, khi không có loại phổ biến giữa A<T>U sự quá tải sẽ bị xoá khỏi danh sách các ứng cử viên thay vì ồn ào phàn nàn.

Cũng có thể thay thế std::common_type hoàn toàn do kết quả tính toán có vấn đề riêng của mình, như được ghi trong DR 2141. Tôi sẽ không phác thảo một sự thay thế bởi vì nó không rõ ràng những gì một giải pháp tốt hơn là, đặc biệt tôi xem xét rằng độ phân giải đề xuất của DR là tồi tệ hơn.

+0

Vì vậy, chỉ để đảm bảo tôi hiểu chính xác những gì xảy ra ở đây, bởi vì tôi thấy nó khá phức tạp; khi tôi sử dụng phiên bản mới này của common_type trong mã của tôi, hãy nói một lần với một loại phổ biến được xác định và một khi không có, SFINAE thực sự sẽ xảy ra trong mã của riêng tôi .. đó là câu của bạn "Bây giờ, khi không có ... " đúng? Và nếu không có kiểu chung nào cả, cho cả hai sự triển khai, thì chúng ta không còn trong tình huống SFINAE nữa, và trong trường hợp đó sẽ tạo ra một lỗi biên dịch thời gian, phải (bis)? – Sheljohn

+0

@ Sh3ljohn Tôi không làm theo những gì bạn có nghĩa là 'một lần với' - đây là một thay thế thả của 'std :: common_type', và là hoàn toàn về nó. Bất cứ nơi nào bạn sử dụng 'std :: common_type' bạn sử dụng cái này thay vào đó: nó có nghĩa là chính xác như nhau, nhưng luôn dẫn đến một lỗi mềm hơn là một lỗi cứng. Nếu đây là về chuyên môn rõ ràng thì không có gì đặc biệt để làm - viết chuyên môn rõ ràng cho 'std :: common_type' và cái này sẽ chọn chúng. –

+0

Có, tôi đã nhận được những gì nó làm. Trong trường hợp của tôi (xem nguồn gốc) nó không thực sự là một chuyên môn mẫu hơn một quá tải mẫu của nhà điều hành +; 'một lần với' được gọi là một trong các khai báo. Tôi chỉ muốn đảm bảo đề xuất của bạn dẫn đến hành vi "loại trừ lẫn nhau" khi gọi nhà điều hành với các loại hợp lệ và việc chuyển loại 'B ' vẫn dẫn đến "lỗi nghiêm trọng". – Sheljohn

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