I have a somewhat contrived piece of code:
#include <functional>
template <typename... ARGs>
auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}
template < typename... ARGs>
auto construct2(std::function<void(int)> p, const ARGs &...args) {}
int main() {
auto p = [](int) {};
construct1<int>(p, 0);
construct2<int>(p, 0);
return 0;
}
Why is the compiler struggling to work out that ARGs... = { int } in the first case? The code compiles okay if I assist the compiler by using std::function<void(int)> in the signature (second case). In both cases, the compiler has no trouble deducing that const ARGs&... should be const int&. Using C++17.
GCC:
main.cpp: In function ‘int main()’:
main.cpp:11:25: error: no matching function for call to ‘construct1<int>(main()::<lambda(int)>&, int)’
11 | construct1<int>(p, 0);
| ^
main.cpp:4:6: note: candidate: ‘template<class ... ARGs> auto construct1(std::function<void(ARGs ...)>, const ARGs& ...)’
4 | auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}
| ^~~~~~~~~~
main.cpp:4:6: note: template argument deduction/substitution failed:
main.cpp:11:25: note: ‘main()::<lambda(int)>’ is not derived from ‘std::function<void(ARGs ...)>’
11 | construct1<int>(p, 0);
|
Clang:
main.cpp:11:5: error: no matching function for call to 'construct1'
construct1<int>(p, 0);
^~~~~~~~~~~~~~~
main.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against '(lambda at main.cpp:10:14)'
auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}
^
1 error generated.