Reputation: 31
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
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
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
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