Search code examples
c++templatesgccclangoverload-resolution

Why C++ compiler chooses wrong function (templates)


I did some tests and encountered this strange behavior.

struct A{};

struct B : A{};

#include <iostream>

template<class T>
void fn2(T const &){
}

void fn2(A const &){
    std::cout << "Here\n";
}

template<class T>
void fn1(){
    T a;

    fn2(a);
}

int main(){
    fn1<B>();
}

I did clean up the code. When run, I expect it prints "here". However it call templated version of fn2().

I did test in godbolt as well. There I rewrited the function fn1() and fn2(), so they return int. At that point, compiler did the right thing.

Here is how I compile:

$ gcc -Wall -Wextra -Wpedantic bug.cc  -lstdc++
$ ./a.out 
$ clang -Wall -Wextra -Wpedantic bug.cc  -lstdc++
$ ./a.out 
$ 

Solution

  • The template version is selected because it's an exact match (with T deduced as B). For the non-template version to be called, the implicit version from B to A is required; then the template version wins in overload resolution.

    You can apply SFINAE with std::enable_if and std::is_base_of to eliminate the template version from the overload set when T is deduced as A or its derived classes.

    template<class T>
    std::enable_if_t<!std::is_base_of_v<A, T>> fn2(T const &){
    }