17

I have the following code:

#include <iostream>

template <typename T>
void f (T) { std::cout << "f(T)" << std::endl; }

template <typename T>
void f (bool) { std::cout << "f(bool)" << std::endl; }

int main ( )
{
    f(true);        // #1 prints f(T)
    f<bool>(true);  // #2 prints f(bool)
}

The #1 line calls f(T), while #2 line calls f(bool).

Why does this happen? And what are the rules for selecting an overloaded template function?

UPDATE

I understood that in the first call compiler is just unable to deduce T while trying to call the second function, so the first is chosen.

In the second call second function is considered a better match on gcc, while the first is chosen under VS2013. Who does the right thing here? By the way, I am still interested in the full description of the process.

lisyarus
  • 15,025
  • 3
  • 43
  • 68
  • 3
    No idea about the rules, but I don't see how the compiler could deduce `T` in your second template, so I don't see how that could be selected without an explicit argument. (But again, I'm quite clueless about template details.) – Mat Mar 14 '14 at 17:13

2 Answers2

21

The unspecialized function templates are also called the underlying base templates. Base templates can be specialized. The overloading rules to see which ones get called in different situations, are pretty simple, at least at a high level:

  • Nontemplate functions are first-class citizens. A plain old nontemplate function that matches the parameter types as well as any function template will be selected over an otherwise-just-as-good function template.

  • If there are no first-class citizens to choose from that are at least as good, then function base templates as the second-class citizens get consulted next. Which function base template gets selected depends on which matches best and is the "most specialized" (important note: this use of "specialized" oddly enough has nothing to do with template specializations; it's just an unfortunate colloquialism) according to a set of fairly arcane rules:

    • If it's clear that there's one "most specialized" function base template, that one gets used. If that base template happens to be specialized for the types being used, the specialization will get used, otherwise the base template instantiated with the correct types will be used.

    • Else (as in your case) if there's a tie for the "most specialized" function base template, the call is ambiguous because the compiler can't decide which is a better match. The programmer will have to do something to qualify the call and say which one is wanted.

    • Else if there's no function base template that can be made to match, the call is bad and the programmer will have to fix the code.

If you want to customize a function base template and want that customization to participate in overload resolution (or, to always be used in the case of exact match), make it a plain old function, not a specialization. And, if you do provide overloads, avoid also providing specializations.

The above is an extract from this post by the Herb Sutter and in the highlighted bullet you can see the source of your problem

EDIT

If you try (don't do it) the above code with Visual Studio 2012, you get

fatal error LNK1179: invalid or corrupt file: duplicate COMDAT '??$f@_N@@YAX_N@Z'

which, as explained here, is because

You did some "trickery" that is invalid C++, and it passed the compiler, but you now have an invalid *.obj, and it chokes the linker.

and the following line is to blame

f(true);        // #1 prints f(T)

so the ambiguity explained in the answer has no guarandeed resolution

Community
  • 1
  • 1
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 1
    And you might have wanted to credit Herb Sutter for your excerpt, cf. http://www.gotw.ca/publications/mill17.htm. – Peter - Reinstate Monica Mar 14 '14 at 17:26
  • So, the second call is ambiguity? And what's with the first call? – lisyarus Mar 14 '14 at 17:29
  • I have read Herb's explanation a few times now and still don't understand it. I think it hinges on the meaning of "most specialized". One would think that f(bool) is more specialized but apparently it isn't, in whatever sense "specialized" is used here. The second thing I don't understand is that there is a difference between f(true) and f(true) since T must be boolean in the first case as well. – Peter - Reinstate Monica Mar 14 '14 at 17:31
  • Base templates are both templates, none of them is specialized (note the _important note: this use of "specialized" oddly enough has nothing to do with template specializations_) maybe the words competent, qualified, able would be more clear. First the base template is chosen and then we move on to specilizations. In this case, the choice of a base template is ambiguous – Nikos Athanasiou Mar 14 '14 at 17:37
  • @lisyarus I am sorry, but I still don't understand why the call _"f(true); // #1 prints f(T)"_ is ambiguous? Should it be the one with _"f(true); // #2 prints f(bool)"_ ? Since in _#1_ the T can't be deduced for the 2nd function template so the first one is a perfect match. But for _#2_, it is ambiguous. What am I missing? – Cheshar Jan 25 '19 at 16:39
4

Actually what you want is a template specialization, which in your case, should be written:

template<> // Without any typename in it!
void f (bool) { std::cout << "f(bool)" << std::endl; }

This works as expected in VS2012.

HiroshimaCC
  • 486
  • 4
  • 11