Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring function templates before defining when overloading

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?

like image 920
AntiElephant Avatar asked May 13 '26 18:05

AntiElephant


2 Answers

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.

like image 148
R Sahu Avatar answered May 15 '26 09:05

R Sahu


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
}
like image 21
T.C. Avatar answered May 15 '26 09:05

T.C.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!