2

I'm a little confused about the idea of using template with <> brackets and without them. When I compiled the code I got the output I wasn't expecting, and didn't figure out why.

For example, let's say I have 2 functions and a template with the same prototype:

using namespace std;

template<typename T> void copy(T a, T b)
{
    cout << "template copy" << endl;
}
void copy(int a, int b)
{
    cout << "int copy" << endl;
}
void copy(string a, string b)
{
    cout << "string copy" << endl;
}

And after compiling the main function:

int main()
{
    copy<int>(1, 2);
    copy<string>("ha", "ha");
    copy("ab", "bc");
    copy(1, 2);
    
    return 0;
}

the output looked like this:

template copy
template copy
template copy
int copy

for the record all the code is written on the same CPP file.

east1000
  • 1,240
  • 1
  • 10
  • 30
sourcerful
  • 35
  • 5
  • 2
    Your code is bad... See [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) and think about [`std::copy`](https://en.cppreference.com/w/cpp/algorithm/copy) – Some programmer dude Sep 09 '21 at 11:35
  • The compiler will select the function with the best/most explicitly matching signature first. So for strings and ints it will select the non-template versions first. In your case for string (number 3) it will select a template for char array. – Pepijn Kramer Sep 09 '21 at 11:35
  • Third call to `copy` is using `copy` – Zereges Sep 09 '21 at 11:37
  • For the one saying my code is bad, this is a simple fast code I made on an online compiler to try understanding the problem of this post, when I code I don't use std, I know it's a bad habbit :) – sourcerful Sep 09 '21 at 11:37
  • if you need to make excuses, it isnt simple code ;) – 463035818_is_not_an_ai Sep 09 '21 at 11:39
  • Rookie mistake... Thank you @Zereges :) – sourcerful Sep 09 '21 at 11:39
  • It ain't no excuse buddy, I literally don't use std, the online compiler adds it. @463035818_is_not_a_number – sourcerful Sep 09 '21 at 11:40
  • `Overloading?`: yes. `copy("ab", "bc")` will have a perfect instantiation of the template for `T` equals `const char*`, whereas it would need an implicit conversion to `std::string` if using the function: https://godbolt.org/z/PjMeY5691 – rturrado Sep 09 '21 at 11:41
  • 1
    Note that `void copy(int, int)` isn't a specialization of `template void copy(T, T)`. – Jarod42 Sep 09 '21 at 11:43
  • *"I got the output I wasn't expecting"*. which is your expectation? – Jarod42 Sep 09 '21 at 11:44
  • @PKramer I tried it with `std::cout << typeid(T).name()` which prints `char const * __ptr64` in msvc. – Zereges Sep 09 '21 at 11:45
  • @Zereges Good test :) I stand corrected – Pepijn Kramer Sep 09 '21 at 11:49

2 Answers2

3

You have to remember that literal strings are really (constant) arrays of characters, which decays to (constant) pointers to char, i.e. const char*.

Since your function taking std::string arguments is not a direct match, and the compiler will not do a conversion, the template overload will be used (as copy<const char*>).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    Also worth mentioning that if you add "using namespace std::string_literals", you can specify a string literal by adding "s", e.g. "ab"s, or "bc"s. See https://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s – Tiger4Hire Sep 09 '21 at 12:00
1

In these calls

copy<int>(1, 2);
copy<string>("ha", "ha");

you explicitly specified the template argument. So the compiler will consider only template functions.

In this call

copy("ab", "bc");

you did not specify the template argument. So the compiler will consider all overloaded functions with the name copy and select the most viable function.

The type of arguments that represent string literals is const char [3].

Due to the standard conversion sequence the arguments are explicitly converted to pointers to first characters of the string literals of the type const char *.

So the compiler can deduce the type of the template argument as the type const char *.

To call the non-template function

void copy(string a, string b)
{
    cout << "string copy" << endl;
}

the compiler needs to use one more conversion (user-defined conversion) to convert the pointers to objects of the type std::string.

So as the template function requires less conversions then it is considered by the compiler as more suitable. And as a result you get the output

template copy

Here is a demonstrative program.

#include <iostream>
#include <iomanip>
#include <type_traits>

template <typename T>
void f( T , T )
{
    std::cout << std::boolalpha << std::is_same<T, const char *>::value << '\n';
}

int main() 
{
    f( "ab", "bc" );
    
    return 0;
}

The program output is

true
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335