I have the following small C++ code sample, but I can't figure out why the compiler works this way, although I have spent quite a lot of time studying cppreference. I would appreciate any explanations! godbolt
#include <type_traits>
template<typename Tp>
struct depend_type
{
constexpr static bool false_ = false;
};
template<typename Tp>
struct cont
{
using x = void;
static_assert(std::is_same_v<Tp, int>);
// if uncomment, will be complie error -> 'cont<Tp>::x' instantiated with 'void (*p)(int) = func;'
// static_assert(depend_type<Tp>::false_);
};
template<typename Tp>
void func(Tp)
{
}
template<typename Tp>
typename cont<Tp>::x func(Tp);
int main(int /* argc */, char * /*argv*/[])
{
// func(1); is ambiguous call
void (*p)(int) = func; // why is not ambiguous?
return 0;
}
void (*p)(int) = func;does overload resolution similarly tofunc(1), with one crucial difference.Both the call and the assignment will first lookup
funcand find the two function templates. Template argument deduction will be done on both templatesTp = intwill be deduced for both of them.Then
Tpwill be substituted into the templates. This is why yourstatic_assert(depend_type<Tp>::false_);will fire because the compiler needs to figure out whattypename cont<Tp>::xis in the return type of the second function.Then the best viable function needs to be found. For overload resolution in the call (
func(1)), neither overload is better than the other (both take an argumentintthat came fromTp). There is nothing else to compare these two overloads, so it is ambiguous.But in the assignment case (
void (*p)(int) = func;), the return type is also considered. In the first function template,voiddidn't come from a template, so it is better than the second function template, where thevoidis a dependent type. So the first function template is chosen.This might be easier to understand with a different example:
This is one of three scenarios where function return type is considered during overload resolution. The second being type conversion operator return types and the third during explicit (full) specialization.