Recently I wrote some code like below:
#include
using namespace std;
inline size_t build_buf_size() {
return 0;
}
template
size_t build_buf_size(const string &t1, const T1 & args) {
int i = 0;
return t1.size() + build_buf_size(i, args);
}
template
size_t build_buf_size(const T &t, const T1 &t1) {
return sizeof(t1) + sizeof(t);
}
int main(int argc, const char *argv[])
{
int a, b, c,d;
string f{"123ffffffffff"};
cout << build_buf_size(f, c) << endl;
return 0;
}
This yields compiling error:
./test1.cc: In instantiation of ‘size_t build_buf_size(const string&, const T1&) [with T1 = int; size_t = long unsigned int; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
./test1.cc:24:32: required from here
./test1.cc:12:38: error: no matching function for call to ‘build_buf_size(int&, const int&)’
return t1.size() + build_buf_size(i, args);
~~~~~~~~~~~~~~^~~~~~~~~
./test1.cc:5:15: note: candidate: size_t build_buf_size()
inline size_t build_buf_size() {
^~~~~~~~~~~~~~
./test1.cc:5:15: note: candidate expects 0 arguments, 2 provided
./test1.cc:10:8: note: candidate: template<class T1> size_t build_buf_size(const string&, const T1&)
size_t build_buf_size(const string &t1, const T1 & args) {
^~~~~~~~~~~~~~
./test1.cc:10:8: note: template argument deduction/substitution failed:
./test1.cc:12:38: note: cannot convert ‘i’ (type ‘int’) to type ‘const string& {aka const std::__cxx11::basic_string<char>&}’
return t1.size() + build_buf_size(i, args);
~~~~~~~~~~~~~~^~~~~~~~~
Where we can see the compiler just ignores the candidate template <class T, class... T1> build_buf_size
Why?
OKay… what my idea was that, build_buf_size
in template<class... T1> build_buf_size
is a dependent name, so the name lookup(find the declaration of the name) should be at the time when the compiler tries to do build_buf_size template instantiation at the second time compiling (Two-Phase Lookup), so the compiler should have already known the declaration of template <class T, class... T1> build_buf_size
.
But actually, the dependent name lookup rules(https://en.cppreference.com/w/cpp/language/dependent_name) requires that “non-ADL lookup examines function declarations with external linkage that are visible from the template definition context”. That’s why the compiler ignores the third build_buf_size……
To solve that issue, just:
inline size_t build_buf_size() {
return 0;
}
template //add declaration here!
size_t build_buf_size(const T &t1, T1 &... args);
template
size_t build_buf_size(const string &t1, T1 &... args) {
return t1.size() + build_buf_size(args...);
}
template
size_t build_buf_size(const T &t1, T1 &... args) {
return sizeof(t1) + build_buf_size(args...);
}
That took me a long time to figure out what is going on exactly. C++ is a language that you need to dig very deep for an explanation even for some problems that every c++ beginners will encounter…