Reputation: 30842
I want to create a templated function that works the same way for const and non-const data, except that it returns a const or non-const pointer as appropriate.
For instance, I want to return a pointer to a matching element in a container:
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
However I can't get this to build for const and non-const calls. If I omit the const from the Container& c
declaration then it can't return a const pointer, but if I change to const Container& c
then I can return a const pointer, but then the non-const case doesn't build.
Is there a way of defining this so that the const
is interpreted as being part of the Container
template parameter so that I only have to define one version of this function?
Upvotes: 5
Views: 223
Reputation: 1164
The simplest is to define both templates and let the compiler find the best match
template <class Container, class Pred>
typename const Container::value_type* getValuePtrIf(const Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
If you object to duplicating code (a worth objection) due to maintenance issues you can try something like the following:
template <class Container, class Pred>
typename const Container::value_type* getValuePtrIf(const Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
return const_cast<Container::value_type*>(
getValuePtrIf(const_cast<const Container &>( c ), pred)
);
}
If it were me, I'd also replace Pred with const Pred & pred)
Robert Ramey
Upvotes: -1
Reputation: 24606
From the code it seems you have C++11 support in your compiler. Then you can probably use decltype
and trailing return types as well:
template <class Container, class Pred>
auto getValuePtrIf(Container& c, Pred pred) -> decltype(&*std::begin(c))
{
auto it=std::find_if(std::begin(c), std::end(c), pred);
return (it!=std::end(c)) ? &(*it) : nullptr;
}
it
will be of whatever type std::begin(c)
gives you (iterator
or const_iterator
), so the type of &(*it)
is the same as of decltype(&*std::begin(c))
.
Upvotes: 6