Sogartar
Sogartar

Reputation: 2175

c++ template function overlading argument deduction with const argument

I am having the following setup:

template <typename T>
void foo(T& t);
void foo(const int& t);

void f()
{
    int i;
    foo(i); //Unresolved reference to "void foo<int>(int &)"
    foo(const_cast<const int&>(i)); //Unresolved reference to "void foo(int const &)"
}

In the first call to foo, the compiler tries to call the template version, since the argument of the non-template one does not match the type of i. In the second call the non-template version is called. I am using the Microsoft C++ compiler version 10. Is this standard behavior? If the type is not exactly matched, even if it only has a const modifier, then the template function is called?

EDIT: I know those two functions don't have definition, I am just pointing out what the linker complains about, to make it more clear what the compiler wants to call.

Upvotes: 1

Views: 474

Answers (3)

Andy Prowl
Andy Prowl

Reputation: 126542

Yes, this behavior is correct according to the C++11 Standard.

In the first case, the argument is a reference to a non-const integer. Both overloads are viable to resolve this call, but the function template allows a perfect match, while the non-template overload requires a qualification conversion.

In the second case, both are a perfect match, but one of the overloads is not a function template, and therefore it is a better candidate than the function template. Per § 13.3.3/1, in fact:

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

— the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ ... ] or, if not that,

F1 is a non-template function and F2 is a function template specialization, or, if not that,

— [...]

Upvotes: 4

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361732

Is this standard behavior? If the type is not exactly matched, even if it only has a const modifier, then the template function is called?

Yes, that is well-defined by the Standard.

If there is no EXACT match, the template is used, because instantiated template version is always a better match than the one which requires conversion (even be it int & to int const& conversion).

Upvotes: 2

Rush
Rush

Reputation: 496

This should work

#include <iostream>

template <typename T>
void foo(T& t) {}
void foo(const int& t){}

void f() 
{
    int i;
    foo(i); //Unresolved reference to "void foo<int>(int &)"
    foo(const_cast<const int&>(i)); //Unresolved reference to "void foo(int const &);
}

int main()
{
    f();
}

Upvotes: -1

Related Questions