2011-10-14 26 views
5

Nếu tôi cóTrọng một chức năng templated với một đa hình một

template<class T> 
TalkyBuffer& operator<<(T const &object) { // Template 
... 
} 
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override 

và một lớp

class A : public TalkySerialisable { 
...} 

Sau đó, nếu tôi thực hiện

TalkyBuffer b; 
A test; 
b << test; 

Sau đó gcc đang kêu gọi các chức năng Template khá so với hàm Ghi đè

Tuy nhiên, nếu tôi xác định cụ thể ghi đè

TalkyBuffer& operator<<(A const &object); // Override without polymorphism 

Sau đó, gcc sẽ chọn thẻ đó. Có cách nào thực tế để ghi đè lên một hàm templated với một lớp trừu tượng?

Tôi đọc điều này nhưng nó không làm sáng tỏ những gì xảy ra khi bạn ném đa hình vào hỗn hợp: http://www.gotw.ca/publications/mill17.htm Ngoài ra tôi không thể tìm thấy giải pháp ở đây nhưng có lẽ tôi đang sử dụng sai cụm từ.

+0

'b << * static_cast (& test)' có hoạt động không? – RedX

Trả lời

1

Khi xác định các chức năng TalkyBuffer& operator<<(TalkySerialisable const &object); You are not trọng. Bạn đang quá tải hàm tmeplated.

Tuy nhiên, khi người khiếu nại thấy b << test;, công cụ tìm kiếm nhà điều hành muốn có số A. Nó có một, đó là chức năng templated mà không yêu cầu cast tự động. Đây là sự lựa chọn tốt nhất.

Chức năng quá tải đòi hỏi một diễn viên tự động (từ A đến TalkySerialisable) trên các thông số để phù hợp với việc kê khai, chứ không phải là sự lựa chọn tốt nhất.

+1

Có anh ta đang quá tải và không chuyên. 'template <> TalkyBuffer & operator << <> (đối tượng và đối tượng TalkySerializable);' sẽ là một chuyên môn. –

+0

Tôi đồng ý với Luc. Không có 'template <>', tôi đang ghi đè. Tuy nhiên, quan điểm của bạn về các chức năng mà không yêu cầu một diễn viên được ưu tiên chắc chắn là thú vị và giải thích hiện tượng này. Tôi tự hỏi là có bất kỳ cách nào xung quanh này trong khi giữ lại một cái gì đó tương đương với chung 'TalkyBuffer & operator << (T const & đối tượng)' –

+1

@Elliot: tốt, để được chính xác, bạn không * ghi đè * nhưng * quá tải *. Ghi đè là về các phương thức ảo (đa hình động) trong khi quá tải là có một số hàm có cùng tên và các tham số khác nhau (một loại đa hình khác, nhưng xảy ra tại thời gian biên dịch). –

0

Một giải pháp sử dụng Boost.enable_if:

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_base_of.hpp> 

template<typename T> 
typename boost::disable_if< 
    boost::is_base_of<TalkySerializable, T>, 
    TalkyBuffer & 
>::type operator<<(T const & object) { // Template for non TalkySerializable 
... 
} 

template <typename T> 
typename boost::enable_if< 
    boost::is_base_of<TalkySerializable, T>, 
    TalkyBuffer & 
>::type operator<<(T const & object); // Template overload for TalkySerializable 

... 

TalkyBuffer b; 
A test; 
b << test; // calls operator<< <A>(A const &), which instantiates 
      // the overload for TalkySerializable 
b << 41; // calls operator<< <int>(int const &), which corresponds to 
     // the "default" overload 

Tôi không chắc chắn đây là giải pháp tốt nhất, nhưng tôi không tìm thấy một tốt hơn: chuyên cung cấp các mẫu không hoạt động hoặc.


Như @Matthieu ghi nhận trong các bình luận, giải pháp trước có nhược điểm lớn mà các mẫu cơ sở cần phải biết rằng nó sẽ bị quá tải, mà là một khớp nối không cần thiết mà gây cản trở khả năng mở rộng.

Để giải quyết vấn đề này, tôi đã đưa ra cách tiếp cận mới bằng cách sử dụng tag dispatching, cùng với các lớp đặc điểm và thời gian biên dịch bằng cách sử dụng Boost.MPL macros.

// TalkyBuffer.hpp 

#include <iostream> 
#include <boost/utility/enable_if.hpp> 
#include <boost/mpl/has_xxx.hpp> 

// defines a metafunction has_talky_buffer_tag<T> that allows us to know at 
// compile-time if T has a member type named talky_buffer_tag 
BOOST_MPL_HAS_XXX_TRAIT_DEF(talky_buffer_tag) 

// tag for the default case 
struct default_talky_buffer_tag {}; 

// trait class for obtaining the tag of a type 
template <typename T, typename Enable = void > 
struct talky_buffer_trait 
{ 
    typedef default_talky_buffer_tag type; 
}; 

// specialization for types that provide a nested typedef 
template <typename T> 
struct talky_buffer_trait<T, 
    typename boost::enable_if<has_talky_buffer_tag<T> >::type> 
{ 
    typedef typename T::talky_buffer_tag type; 
}; 


struct TalkyBuffer 
{ 
    // Insertion operator, which calls an implementation function that can 
    // be overloaded depending on the tag 
    template<typename T> 
    TalkyBuffer & operator<<(T const & object) 
    { 
     typename talky_buffer_trait<T>::type tag; 
     return insertionOperatorImpl(*this, object, tag); 
    } 
}; 

// default implementation 
template <typename T> 
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, T const & object, 
    default_talky_buffer_tag) 
{ 
    std::cout << "default"; 
    return buf; 
} 


//------- 
// TalkySerializable.hpp 

struct TalkySerializable 
{ 
    struct tag {}; 
    typedef tag talky_buffer_tag; 
}; 

// A inherits from the nested typedef 
struct A : public TalkySerializable {}; 

// implementation for TalkySerializable objects 
template <typename Serializable> 
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, Serializable const & object, 
    TalkySerializable::tag) 
{ 
    std::cout << "specialized"; 
    return buf; 
} 


//------- 
int main() 
{ 
    TalkyBuffer b; 
    A test; 
    b << test; // outputs "specialized" 
    b << 41; // outputs "default" 
} 

Để cung cấp triển khai mới của các nhà điều hành chèn cho một loại nhất định T, người ta cần phải cung cấp một loại mới để hoạt động như một thẻ (TypeSerializable::tag trong ví dụ của chúng tôi), cung cấp một cách để kết hợp T với thẻ mới (hoặc bằng cách sử dụng một typedef lồng nhau như trong ví dụ, hoặc bằng cách chuyên lớp đặc điểm: template <> talky_buffer_trait<T> { typedef new_tag type };), và cuối cùng quá tải chức năng thực hiện (insertionOperatorImpl trong ví dụ).

+0

Tôi thích một cách ít xâm lấn hơn. Các khả năng phát hiện hoặc các đặc điểm sẽ cho phép mẫu cơ sở không thể nhận biết được các loại mà các chuyên ngành tồn tại. –

+0

@Matthieu: vâng, thực tế là mẫu cơ sở phải biết rằng có quá tải đang làm phiền tôi. Tôi sẽ cố gắng đưa ra một giải pháp tốt hơn. –

+0

@Matthieu: vấn đề là các mẫu và kế thừa thường hoạt động khá tệ với nhau. Ví dụ, nếu tôi muốn sử dụng một đặc điểm lớp, tôi sẽ không thể chuyên nó cho tất cả 'TalkySerializable', vì' trait 'sẽ không phù hợp với chuyên môn. Đây là một vấn đề tôi thường tình cờ gặp phải, và luôn luôn cố định với cách giải quyết không hoàn toàn hài lòng tôi, vì vậy nếu bạn có một số hiểu biết về chủ đề này, tôi sẽ rất vui khi nghe họ! –

1

Tôi nghĩ rằng nó có thể sử dụng một giải pháp đơn giản function dựa, tái sử dụng chức năng quá tải cho nguồn gốc.

struct specialized {}; 
struct generic {}; 

template <class T> 
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) { 
    ... 
} 

generic dispatch(...) {} // always picked up last in overload resolution 

template <class T> 
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template 
    return serialize(*this, object, dispatch(object)); 
} 

Bây giờ, chúng ta hãy thực hiện lớp tùy chỉnh của bạn:

TalkyBuffer& serialize(TalkyBuffer& buffer, 
         TalkySerialisable const& object, 
         specialized); 

specialized dispatch(TalkySerialisable const&) {}  

Và tạo ra một nguồn gốc một:

class A: public TalkySerialisable {}; 

Vì vậy, những gì sẽ xảy ra?

  • TalkyBuffer::operator<<(T const&) sẽ được nhặt
  • khi cố gắng để giải quyết tình trạng quá tải cho serialize, nó sẽ lần đầu tiên tính toán kết quả của dispatch
  • khi giải quyết hậu quả của dispatch, là một trận đấu tốt hơn so với dispath(...), do đó loại trả về là specialized
  • chung serialize không thể được sử dụng (không có chuyển đổi từ specialized thành generic), do đó, thừa kế đá trong
+0

Rất tốt, sử dụng chức năng quá tải để lấy thẻ cho việc gửi đi là tốt hơn nhiều so với đặc điểm kiểu hoạt động liền mạch với chuyển đổi kế thừa và tiềm ẩn. –

+0

@LucTouraille: Tôi chỉ ước mình có thể làm cho nó bớt vụng về, nhưng nếu tôi thử thay thế đối số 'generic' trong' serialize' trực tiếp bằng '...' tôi nhận được quá tải không rõ ràng: x –

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