Insub  Im
Insub Im

Reputation: 31

Is there any generic method for smart pointers and raw pointers?

I have a question about c++ template.

template <class Container>
void tryTriggers(const Container& entities)
{
  for (Container::const_iterator ent = std::begin(entities);ent != std::end(entities); ++ent)
  {
    if ((*ent)->isReadyForTriggerUpdate() && (*ent)->isAlive())
    {
      for (TriggerList::const_iterator trg = std::begin(_triggers);trg != std::end(_triggers); ++trg)
      {
         //Try(..) is a method takes *entity(entity's pointer) for parameters.
         //But my container was implemented with unique_ptr. 
         //ex) vector<unique_ptr<entity>> v;
         //So I used get() method for acquire raw pointer.

        (*trg)->Try((*ent).get());
      }
    }
  }
}

The code is template member function for some containers.

It only works with class witch have isReadyForTriggerUpdate() and isAlive() in it.

Try(..) is a method takes *entity(entity's pointer) for parameters.

In my case, I use unique_ptr int containers so I have to use get() method for get raw pointer.

The function doesn't make any problems but.. if I use some container with raw pointers like

vector <entity*> v;

then it will make problem.

Question: I want to make it more generic so that it can works with raw pointers and smart pointers. Is there any solution about this?

In STL, there is std::begin(con) for solve problems related with iterating problem in con.begin(). So I expect some generic method like

std::begin(con)

for above problem.

Upvotes: 3

Views: 697

Answers (3)

Francis Labelle
Francis Labelle

Reputation: 21

(*ent).get()

Since I don't know anything about the rest of your program, I assume this is the only line that prevents your function from working: get is a member function of smart pointers but it can't be used with raw pointers. There are two solutions I see that could solve this:

Solution 1

Make your Try function work with smart pointers as well as raw pointers. For example:

class A
{
    public:
        template <class SmartPointer>
        void Try(const SmartPointer& pointer)
        {
            Try(pointer.get());
        }

        void Try(entity* pointer)
        {
            /* Your code here */
        }
}

Solution 2

If you can't change the class that's being used then you can make a few functions to convert the abstract type you're working on to a raw pointer. One function for smart pointers and one for raw pointers.

template <class SmartPointer>
typename SmartPointer::element_type* getRawPointer(Pointer const& p)
{
    return p.get();
}

template <typename T>
T* getRawPointer(T* p)
{
    return p;
}

Where SmartPointer::element_type is the type used by the smart pointer (int for a std::unique_ptr<int>). Note that you have to declare it as typename SmartPointer::element_type to tell the compiler that this is indeed a type.

Edit: Changed SmartPointer::pointer to SmartPointer::element_type* to make it work with newer smart pointers.

Upvotes: 0

Ami Tavory
Ami Tavory

Reputation: 76317

Asides from @Slava's quite correct answer, you can, in general, always write a template function and specialize it for a raw pointer:

template<class T>                                                                                                                           
auto find_address_of(T &&p) -> decltype(p.get())
{
    return p.get();
}

template<typename T>
T *find_address_of(T *p)
{
    return p;
}

Upvotes: 3

Slava
Slava

Reputation: 44258

If you take address of dereferenced pointer instead of calling std::unique_ptr::get() that should work in both cases:

(*trg)->Try(&**ent);

Upvotes: 2

Related Questions