7

What can I use to dereference a template argument if it's a pointer (or a smart pointer), or leave it as is if it's not?

template<class T> void subf(const T& item)
{
    item.foo();
}

template<class T> void f(const T& item)
{
    subf(magic_dereference_function(item));
}

Anything in Boost is an option.

Xeo
  • 129,499
  • 52
  • 291
  • 397
Alex B
  • 82,554
  • 44
  • 203
  • 280

4 Answers4

12
template <typename T>
T& maybe_deref(T& x) { return x; }

template <typename T>
T& maybe_deref(T* x) { return *x; }

You'll have to add overloads for smart pointers individually. There's no way to detected if a class is a "smart pointer". You could detect the presence of operator->, but that doesn't mean it's a smart pointer.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
  • This is what I have at the moment. I hoped there is a smart pointer solution not involving a lot of mind-numbing code. – Alex B Jun 15 '11 at 07:55
  • @Alex: It's not that mind numbing, is it? btw, I can't say for sure, but what you are doing smells awfully bad. Could you describe what the wider purpose of this function is supposed to be? Knowing this, there may be a better high level solution that avoids the need for such a function. – Peter Alexander Jun 15 '11 at 07:58
  • The `const` overloads are not necessary. Without them, the typename `T` itself will be deduced as `const` as appropriate. – fredoverflow Jun 15 '11 at 13:59
3

How about an overload?

template<class T>
T& deref(T& t){
  return t;
}

template<class T>
T& deref(T*& t){
  return *t;
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
1

http://www.boost.org/doc/libs/1_44_0/libs/type_traits/doc/html/boost_typetraits/reference/is_pointer.html

?

Sergey Miryanov
  • 1,820
  • 16
  • 29
  • 1
    "Users wanting a trait to detect smart pointers should create their own. However, note that there is no way in general to auto-magically detect smart pointer types, so such a trait would have to be partially specialised for each supported smart pointer type." – Luc Danton Jun 15 '11 at 07:47
0

I don't know whether this suits your pattern, but for member function references, boost::bind and boost::phoenix already do what you want:

 struct T 
 {
      void f(int) const {} 
 };


 T instance;
 T* pointer = new T();
 boost::shared_ptr<T> shared(new T());

 boost::bind( & T:f, instance, 1);              // stores instance by value
 boost::bind( & T:f, boost::ref(instance), 2);  // stores instance by ref
 boost::bind( & T:f, boost::cref(instance), 3); // stores instance by const ref

 boost::bind( & T:f, pointer, 4);               // dereferences the pointer

 boost::bind( & T:f, shared, 5);                // dereferences the smart pointer

_You can even use typetraits to let boost::bind/phoenix know about your own smart pointer (or any type that you want dereferenced with operator* and operator-> when used)_

BenMorel
  • 34,448
  • 50
  • 182
  • 322
sehe
  • 374,641
  • 47
  • 450
  • 633