In the following example if you change auto
to void
the program will print 1
instead of 0
. Why is that happening. What lookup rules are applicable here?
#include <iostream>
struct X { operator int() const; };
std::false_type f(int);
template <typename T>
auto f2(T t) {
std::cout << decltype(f(t)){};
}
decltype(f2(X{}))*_;
std::true_type f(X);
int main() {
f2(X{});
}
Switching the return type between void
and auto
changes whether decltype(f2(X{}))
performs the implicit instantiation of f2
.
When the return type is spelled out as void
, the declaration is sufficient; the definition doesn't need to be instantiated. Then f2<X>
has one point of instantiation - at the end of the translation unit, right after main
. At this point, the two overfloads of f
are visible, and f(X)
is chosen as a better match.
When the return type is auto
, the definition needs to be instantiated. Then f2<X>
has two points of instantiation - one after main
, and an extra one at the decltype
line. Now, different points of instantiation give the template specialization different meanings, at which point the program is ill-formed, no diagnostic required. Apparently, your implementation happens to choose the first point of instantiation, where only one f
overload is visible.
[temp.point]/1 For a function template specialization ... the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
[temp.point]/8 A specialization for a function template ... may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation... If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.