Search code examples
c++parameter-passingimplicit-conversion

Compilation error in template when const is removed


template<typename T>
void func(const T &x) {
    cout << "base template "<<x<<"\n";
}

template<>
void func(const int &x) {
    cout << "int specialization "<<x<<"\n";
}

template<>
void func(const double &x) {
    cout << "double specialization "<<x<<"\n";
}

int main() {
    int five = 5;
    func(five); // prints int specialization 5
    double d = 3.14;
    func<int>(d); // prints int specialization 3
}

Now with const removed

template<typename T>
void func( T &x) {
    cout << "base template "<<x<<"\n";
}

template<>
void func( int &x) {
    cout << "int specialization "<<x<<"\n";
}

template<>
void func( double &x) {
    cout << "double specialization "<<x<<"\n";
}

int main() {
    int five = 5;
    func(five); // prints int specialization 5
    double d = 3.14;
    func<int>(d); // throws compile error
}

Why do I get a compilation error in func<int>(d) where as in the const version everything compiled fine ?

Error C2664 'void func(int &)': cannot convert argument 1 from 'double' to 'int &'

I came across this when I was trying out some examples on my own for template specialization.

I'm looking for reading links and posts that might be helpful.


Solution

  • The issue is not actually related to templates:

    Your double d needs to be converted to an int in order to be an argument for a function expecting an int reference.

    But since the converted int is a temporary (i.e. a R-value) it cannot be bound to an int &, but only to a const int &.

    You can observe this without any template:

    void func1(const int& x) 
    {
    }
    
    void func2(int& x) 
    {
    }
    
    int main() 
    {
        double d = 3.14;
        func1(d);   // This compiles.
        func2(d);   // This does not. Error on MSVC: cannot convert argument 1 from 'double' to 'int &'
    }