Reputation: 1147
Could you please explain why I'm having error: call of overloaded ‘func(const Test&)’ is ambiguous
despite the fact that I use explicit template instantiation?
#include <iostream>
struct Test {
};
void func(const Test &) {
std::cout << "By Reference" << std::endl;
}
void func(const Test) {
std::cout << "By Value" << std::endl;
}
template <typename... TArgs>
void wrap(TArgs... args) {
func(args...);
}
int main() {
Test t;
wrap<const Test &>(t);
return 0;
};
EDIT
The reason of ambiguity is a combination of two factors. The first is that simple overload rules applied in the call func(args...)
. The second is that simple functions cannot be overloaded by value and const reference. To ensure, one may replace the call wrap<const Test &>(t)
with func(static_cast<const Test &>(t))
. The error will still be there.
To solve the problem, one may use function template for func
and value vs const reference template specialization as showed in the example provided by @lubgr
Thanks everybody to help me to demystify the concept.
Upvotes: 5
Views: 396
Reputation: 38267
With the wrap
function template explicitly instantiated, imagine the compiler being in the wrap
instantiation, knowing that Targs...
really is const Test&
. Which function overload should then be chosen? It can't prefer one, because the template parameter of wrap
doesn't propagate to an ordinary (non-template) function. Instead, simple overload rules apply.
You can see the difference and fix the issue if you change func
to be a function template, too:
template <class T> void func(T);
template <> void func<const Test&>(const Test&) {
std::cout << "By Reference" << std::endl;
}
template <> void func<const Test>(const Test) {
std::cout << "By Value" << std::endl;
}
The appropriate specialization is called when you explicitly ask for it, then.
template <typename... TArgs>
void wrap(TArgs... args) {
func<TArgs...>(args...); // Note, the type is specified here, again.
}
Upvotes: 2