C++ 具有可以是指针类型或非指针类型的模板参数

C++ 具有可以是指针类型或非指针类型的模板参数,c++,templates,pointers,c++11,C++,Templates,Pointers,C++11,假设我有这样的东西: template <class T> void do_something(T t){ pass_it_somewhere(t); t->do_something(); } 模板 无效做某事(T){ 把它传递到某个地方(t); 做某事; } 现在,允许T为指针类型或非指针类型将非常有用。函数do_something(…)基本上可以处理指针和非指针,除了t->do_something()之外。对于指针,我需要一个->,对于非指针,我需要一个来访问成

假设我有这样的东西:

template <class T>
void do_something(T t){
  pass_it_somewhere(t);
  t->do_something();
}
模板
无效做某事(T){
把它传递到某个地方(t);
做某事;
}
现在,允许
T
为指针类型或非指针类型将非常有用。函数
do_something(…)
基本上可以处理指针和非指针,除了
t->do_something()
之外。对于指针,我需要一个
->
,对于非指针,我需要一个
来访问成员


有没有办法让
T
接受指针和非指针?
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();
}
模板
无效做某事(T){
把它传递到某个地方(t);
t、 做某事;
}
模板
无效做某事(T*T){
把它传递到某个地方(t);
做某事;
}
解决方案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();
}
A类
{
公众:
void do_something()常量{}
常量A*运算符->()常量{返回此;}
};
模板
无效做某事(T){
把它传递到某个地方(t);
做某事;
}

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

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;
}
模板
std::如果取消引用(t&t){
返回*t;
}
模板
std::启用\U如果\U t::值,t&>取消引用(t&t){
返回t;
}
并在功能中使用它作为:

template <class T>
void do_something(T t){
  pass_it_somewhere(dereference(t));
  dereference(t).do_something();
}
模板
无效做某事(T){
把它传递到某个地方(去引用(t));
去引用(t)。做某事();
}


这样,您将只能处理具体版本的
T

还有另一个解决方案:标签分发

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();
    }
}
名称空间详细信息{
结构标记_值{};
结构标记_ptr{};
模板结构分派{using type=tag_value;};
模板结构分派{using type=tag_ptr;};
模板
无效do_调用(tV,标记值)
{
v、 call();
}
模板
无效do_呼叫(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

}
模板
虚空做某事(未知)
{
不要打电话(未知,
typename详细信息::分派::类型{});
//ADL发现
}


.

s/specialize/重载我认为这是最好的答案,因为它产生了非常可读和简洁的代码。谢谢:-)虽然这个问题有一些有趣的答案,但我最终还是在这里找到了一个很好的解决方案: