2016-04-28 161 views
6

假设我有这样的:有一个模板参数可以是指针类型或非指针类型

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

现在T被允许成为一个指针 - 或非指针类型将是有益的。函数do_something(...)基本上可以处理指针和非指针,除了t->do_something()。对于指针,我需要一个->,对于非指针,我需要一个.来访问成员。

有没有办法让T接受指针非指针?

回答

9

你可以如下创建取消引用机制:

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; 
} 

,并用它在你的函数为:

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

Live Demo

这样,你必须只用混凝土做版本T

+1

我认为这是最好的答案,因为它会产生非常可读和简洁的代码。谢谢 :-) – Michael

7

Soultion 1只

使用模板特:

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(); 
} 

溶液2

在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

这是一个解决方案,但在我的情况下会非常不方便... – Michael

+4

s/specialize/overload – Barry

2

又一个解决方案:标签调度。

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(); 
    } 
} 

那么你的函数变为:

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

相关问题