Reputation: 1257
C++ Primer 5th Edition has a snippet of advice at the end of chapter 16.3 (a chapter discussing function template overloading):
Declare every function in an overload set before you define any of the functions. That way you don’t have to worry whether the compiler will instantiate a call before it sees the function you intended to call.
So is this telling me that in choosing the candidate and viable functions during overload resolution it is possible the compiler might instantiate a function template that isn't chosen in the end? I tried to see whether this might actually happen:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <typename T> void test(T*) { }
int main(){
int *q = nullptr;
test(q); //test(T*) should be the best match
}
This program would throw a compiler error if test(T const &)
was instantiated in any form, except the program compiles fine as expected. So what kind of compilation mishap is that tip trying to guard me from? When would it ever instantiate a function before it saw the function I was trying to call?
Upvotes: 3
Views: 101
Reputation: 137315
I've seen plenty of SO questions that is some variation of
template<class T, class... Ts>
T sum(T t, Ts... ts) { return t + sum(ts...); }
// ^ |
// |--------------------------------
// only one visible in
// definition context
template<class T>
T sum(T t) { return t; }
int main() {
sum(1, 2); // doesn't compile
}
(The return type isn't perfect, but you get the idea.)
And then people are surprised when it doesn't compile.
Or, even more fun,
template<class T> void f(T t) { f((int)t); }
void f(int) { /*...*/ }
int main() {
f(1L); // infinite recursion
}
Upvotes: 2
Reputation: 206607
The author is warning you of this:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
int main(){
int *q = nullptr;
test(q); //test(T*) will not be matched.
}
template <typename T> void test(T*)
{
}
And these:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <> void test<int>(int const &);
void test(int *);
int main(){
int *q = nullptr;
test(q); //test(int*) should be the best match
int a;
test(a); // test<int>(int const&) should be the best match
}
template <> void test<int>(int const &)
{
}
void test(int *)
{
}
If you don't provide declarations of
template <> void test<int>(int const &);
void test(int *);
before main
, they won't be matched in main
.
Upvotes: 5