Kemal - 1 year ago 57

C++ Question

Consider the code below, where the intention is to overload

`std::count_if()`

`// overload for call with predicate`

template<typename Cont_T, typename Pred_T>

typename std::iterator_traits<typename Cont_T::iterator>::difference_type

count_if(const Cont_T& c, Pred_T p) {

return std::count_if(c.begin(), c.end(), p);

}

// overload for call with value

template<typename Cont_T, typename T = typename Cont_T::value_type>

typename std::iterator_traits<typename Cont_T::iterator>::difference_type

count_if(const Cont_T& c, const T& val) {

return std::count_if(c.begin(), c.end(), val);

}

int main() {

using namespace std;

vector<int> v{1,2,3};

count_if(v, 2); // ambiguous call

return 0;

}

The result is a compiler error that says the call is ambiguous.

Is there a way to make this work?

Answer Source

If you are using standard containers (with `value_type`

^{1}), you could try:

```
// overload for call with predicate
template<typename Cont_T>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type
count_if(const Cont_T& c, std::function<bool(typename Cont_T::value_type)> p) {
return std::count_if(c.begin(), c.end(), p);
}
// overload for call with value
template<typename Cont_T>
typename std::iterator_traits<typename Cont_T::iterator>::difference_type
count_if(const Cont_T& c, const typename Cont_T::value_type& val) {
return std::count(c.begin(), c.end(), val);
}
```

By forcing the type of the second parameter (not making it a template parameter), you avoid ambiguity. However, I would probably not do that and would stick to the standard version which is `count`

/ `count_if`

.

_{1 If you cannot rely on Cont_T::value_type, you could replace it by a more "general" decltype(*c.begin())) or something alike.}