Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap a templated function to work on const and non-const data

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?

like image 439
the_mandrill Avatar asked Nov 11 '13 12:11

the_mandrill


People also ask

How is it possible to have both const and non-const version of a function?

There are legitimate uses of having two member functions with the same name with one const and the other not, such as the begin and end iterator functions, which return non-const iterators on non-const objects, and const iterators on const objects, but if it's casting from const to do something, it smells like fish.

Can const function call non-const function?

const member functions may be invoked for const and non-const objects. non-const member functions can only be invoked for non-const objects. If a non-const member function is invoked on a const object, it is a compiler error.

How do I remove a const?

The statement int* c = const_cast<int>(b) returns a pointer c that refers to a without the const qualification of a . This process of using const_cast to remove the const qualification of an object is called casting away constness. Consequently the compiler does allow the function call f(c) .


Video Answer


1 Answers

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)).

like image 100
Arne Mertz Avatar answered Oct 17 '22 17:10

Arne Mertz