2016-04-28 27 views
6

Giả sử tôi có một cái gì đó như:Có một tham số mẫu có thể được loại con trỏ hoặc không con trỏ kiểu

template <class T> 
void do_something(T t){ 
    pass_it_somewhere(t); 
    t->do_something(); 
} 

Bây giờ nó sẽ là hữu ích mà T được phép trở thành một pointer- hoặc một loại phi con trỏ . Chức năng do_something(...) về cơ bản có thể xử lý con trỏ và con trỏ, ngoại trừ t->do_something(). Đối với con trỏ, tôi sẽ cần một -> và cho con trỏ không, tôi sẽ cần một . để truy cập các thành viên.

Có cách nào để thực hiện T chấp nhận con trỏ không phải con trỏ không?

Trả lời

9

Bạn có thể tạo ra một cơ chế dereference như sau:

template<typename T> 
std::enable_if_t<std::is_pointer<T>::value, std::remove_pointer_t<T>&> dereference(T& t) { 
    return *t; 
} 

template<typename T> 
std::enable_if_t<!std::is_pointer<T>::value, T&> dereference(T& t) { 
    return t; 
} 

và sử dụng nó trong chức năng của bạn như:

template <class T> 
void do_something(T t){ 
    pass_it_somewhere(dereference(t)); 
    dereference(t).do_something(); 
} 

Live Demo

Bằng cách này bạn sẽ phải làm chỉ với các phiên bản bê tông của T.

+1

Tôi nghĩ đó là câu trả lời hay nhất vì nó dẫn đến mã rất dễ đọc và súc tích. Cảm ơn :-) – Michael

7

soultion 1

Sử dụng mẫu chuyên môn:

template <class T> 
void do_something(T t){ 
    pass_it_somewhere(t); 
    t.do_something(); 
} 

template <class T> 
void do_something(T* t){ 
    pass_it_somewhere(t);  
    t->do_something(); 
} 

Giải pháp 2

Thêm một nhà điều hành con trỏ người dùng định nghĩa trong lớp T:

class A 
{ 
public: 
    void do_something() const {}   
    const A* operator->() const { return this; } 
}; 

template <class T> 
void do_something(T t){ 
    pass_it_somewhere(t);  
    t->do_something(); 
} 
+0

Đó là giải pháp, nhưng sẽ rất bất tiện trong trường hợp của tôi ... – Michael

+4

s/chuyên/quá tải – Barry

2

Một giải pháp khác: gửi thẻ.

namespace detail { 
    struct tag_value {}; 
    struct tag_ptr {}; 

    template <bool T> struct dispatch  { using type = tag_value; }; 
    template <>  struct dispatch<true> { using type = tag_ptr; }; 

    template <class T> 
    void do_call(T v, tag_value) 
    { 
     v.call(); 
    } 

    template <class T> 
    void do_call(T ptr, tag_ptr) 
    { 
     ptr->call(); 
    } 
} 

Sau đó, chức năng của bạn trở thành:

template <class T> 
void do_something(T unknown) 
{ 
    do_call(unknown, 
       typename detail::dispatch<std::is_pointer<T>::value>::type{}); 

    // found by ADL 

} 

Live Example.

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