Reputation: 5965
For the following code:
#include <iostream>
#include <vector>
template <class T>
inline auto foo(const T* A)
{
return A[0];
}
template <class T>
struct impl
{
template <typename F>
static auto bar(const T& A, F func)
{
return func(&A[0]);
}
};
int main()
{
std::vector<size_t> A = {2, 3, 4};
std::cout << impl<decltype(A)>::bar(A, &foo) << std::endl;
return 0;
}
I get (with C++14 using clang on macOS) that
main.cpp:23:18: error: no matching function for call to 'bar'
std::cout << impl<decltype(A)>::bar(A, &foo) << std::endl;
^~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:17: note: candidate template ignored: couldn't infer template argument 'F'
static auto bar(const T& A, F func)
^
1 error generated.
My question is: Why? How can I fix it?
Upvotes: 2
Views: 127
Reputation: 122133
The issue is actually from foo
not from impl
. foo
is a template and you will an error also for:
auto x = &foo;
source>:23:15: error: unable to deduce 'auto' from '& foo'
23 | auto x = &foo;
| ^~~
<source>:23:15: note: couldn't deduce template parameter 'auto'
I am not suggesting this a the "right" solution, it is just to show how in principle you can get a pointer to the right instantiation of foo
:
int main()
{
std::vector<size_t> A = {2, 3, 4};
std::cout << impl<decltype(A)>::bar(A,
static_cast<size_t(*)(const decltype(A)::value_type*)>(&foo)) << std::endl;
return 0;
}
Or the more readable (thanks to @StoryTeller):
int main()
{
std::vector<size_t> A = {2, 3, 4};
//auto x = &foo<decltype(A)::value_type>;
std::cout << impl<decltype(A)>::bar(A,&foo<decltype(A)::value_type>) << std::endl;
return 0;
}
Note that gcc
does emit the same error as for the original. This appears to be a bug in gcc. Removing the //
from the line above magically makes it compile also with gcc even though x
is not used. The bug seems to be fixed in gcc-trunk: https://godbolt.org/z/noqGEP (see also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54111).
Upvotes: 2
Reputation: 37607
This should work (without lambda):
#include <iostream>
#include <vector>
template <class T>
auto foo(const T* A)
{
return A[0];
}
template <class T>
struct impl
{
template <typename F>
static auto bar(const T& A, F func)
{
return func(&A[0]);
}
};
int main()
{
std::vector<size_t> A = {20, 3, 4};
std::cout << impl<decltype(A)>::bar(A, &foo<size_t>) << std::endl;
return 0;
}
but gcc fails for some reason (clang and msvc are fine with that).
Upvotes: 1
Reputation: 180500
foo
is the name of a template, not the name of a function. bar
requires a type, not a template. Fortunately lambda expressions are a fast easy way to wrap generic function into an object type that can be known and do the dispatch for you. That would give you
std::cout << impl<decltype(A)>::bar(A, [](const auto& var){ return foo(var); })
<< std::endl;
Upvotes: 3