Shaun Ziqin Rong Shaun Ziqin Rong - 4 months ago 21
C++ Question

No matching function call for template specialization of const char*

I am trying to learn the template specialization for C++ language, coming across this situation I can't solve myself. Codes below:

#include <vector>
#include <iostream>
#include <string>
#include <cmath>

using namespace std;
size_t count(const vector<string> &, const char* const &);

template <typename T>
size_t count(const vector<T>& v, const T& find) {
size_t c = 0;
for (auto ele : v) {
if (ele == find)
++c;
}
return c;
}

template <>
size_t count(const vector<double> &v, const double &find) {
size_t c = 0;
for (auto ele : v) {
if (abs(ele - find) < 0.0001)
++c;
}
return c;
}

template <>
size_t count(const vector<const char*> &v, const char* const &find) {
size_t c = 0;
for (auto ele : v) {
if (strcmp(ele, find) == 0)
++c;
}
return c;
}

size_t count(const vector<string> &v, const char* const &find) {
size_t c = 0;
for (auto ele : v) {
if (strcmp(ele.c_str(), find) == 0)
++c;
}
return c;
}

int main() {
vector<double> vd{0.1, 0.1, 0.2};
cout << count(vd, 0.1) << endl;
vector<string> vs{"I", "you", "I"};
cout << count(vs, "I") << endl;
vector<const char*> vc{"I", "you", "I"};
cout << count(vc, "I") << endl;
return 0;
}


Compiling this code,
cout << count(vc, "I") << endl;
will report error about not finding a matching function call.

However, I deliberately declare a specialization for this function call, namely
template <> size_t count(const vector<const char*> &v, const char* const &find)


What is wrong here?

Thank you.

Answer

The way specializations work is: first deduction happens against the primary template, and then any specializations are considered. When you call count(vc, "I"), we perform deduction on

template <typename T>
size_t count(const vector<T>& v, const T& find)

which will deduce const char* for the first T, but const char[2] for the second T. Since those don't match, deduction fails. It doesn't matter what your specializations are (which are wrong anyway, for the same reason).


Instead of specializing and using the same T in both places, simply provide two overloads:

template <class Container, class ELem>
size_t count(Container const& c, Elem const& elem); // uses operator==

template <class Container, class UnaryPredicate>
size_t count(Container const& c, UnaryPredicate f); // uses f()

That way, you can write:

count(vd, [](double d){return abs(d-0.1) < 0.00001;});
count(vc, [](const char* p){ return strcmp(p, "I") == 0; });

without added duplication.

Comments