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.
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,
— [...]
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).
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();
}
Related
Is this code valid?
template<bool b>
struct s {
void f() const {
}
static void f() requires b {
}
};
void g() {
s<true>().f();
}
clang says yes, but gcc says no
<source>: In function 'void g()':
<source>:10:20: error: call of overloaded 'f()' is ambiguous
10 | s<true>().f();
| ~~~~~~~~~~~^~
<source>:3:14: note: candidate: 'void s<b>::f() const [with bool b = true]'
3 | void f() const {
| ^
<source>:5:21: note: candidate: 'static void s<b>::f() requires b [with bool b = true]'
5 | static void f() requires b {
| ^
Compiler returned: 1
https://godbolt.org/z/f4Kb68aee
If we go through [over.match.best.general], we get:
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 [...]
The only argument is the object argument, and we have earlier that:
If F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,
So the premise holds: all arguments for one function have a conversion sequence no worse than the conversion sequence for the other function. So we move on to our tiebreakers...
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
The only argument that we could have a better conversion sequence for is the object argument, and as established, that one is equivalent. So this tiebreaker does not apply.
the context is an initialization by user-defined conversion (see [dcl.init], [over.match.conv], and [over.match.ref]) and [...]
Nope.
the context is an initialization by conversion function for direct reference binding of a reference to function type, [...]
Nope.
F1 is not a function template specialization and F2 is a function template specialization, or, if not that,
Nope.
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,
Nope.
F1 and F2 are non-template functions with the same parameter-type-lists, and F1 is more constrained than F2 according to the partial ordering of constraints described in [temp.constr.order], or if not that,
Aha! In this example, we have non-template functions with the same parameter-type-lists (both are just empty). The static member function is constrained and the non-static member function is not constrained, which is the most trivial kind of "more constrained" (see [temp.constr.order]).
As such, I think that clang (and msvc) are correct to accept the program and gcc is incorrect to reject it. (submitted 103783).
Your code is ill-formed according to C++20 standard class.static.mfct#2:
There shall not be a static and a non-static member function with the same name and the same parameter types ([over.load]).
There is no exception here for the presence of requires-clause to differentiate member functions, only same name and the same parameter types. And it is exactly our case: the same name is f, and the same parameter types is empty set.
So Clang and MSVC are wrong in accepting the code. But the diagnostics of GCC is definitely confusing.
With some minor tweaks in the code (removed const in not-static member function and get its address in the code), Clang and MSVC also show to have big problems with it:
template<bool b>
struct s {
void f() {}
static void f() requires b {}
};
int main() {
s<true>().f();
void (s<true>::*x)() = &s<true>::f;
}
Demo: https://gcc.godbolt.org/z/vdq9j63Gs
This question already has answers here:
Why does a function declaration with a const argument allow calling of a function with a non-const argument?
(4 answers)
Closed 5 years ago.
Code
class A
{
public:
void f(const int i);
};
void A::f(int i)
{
std::cout<<++i<<std::endl;
}
int main()
{
A a;
a.f(1);
}
Why compiler does not give an error in this case ? Why the definition overrides the constant argument ?
Also, when the argument is of type reference (&) the compiler throws error but why not in this case ?
Is there any compiler flag to enable warning on these mentioned cases ?
I am interested more from compiler error POV. Because one can easily put declaration (const) and definition(non-constant) differently and still compiler accepts it. If a mistake can be made it will eventually be made. Why can't compiler complain when there is such difference present.
From 11.3.5 Functions [dcl.fct]:
A single name can be used for several different functions in a single
scope; this is function overloading (Clause 16). All declarations for
a function shall agree exactly in both the return type and the
parameter-typelist. The type of a function is determined using the
following rules. The type of each parameter (including function
parameter packs) is determined from its own decl-specifier-seq and
declarator. After determining the type of each parameter, any
parameter of type “array of T” or of function type T is adjusted to be
“pointer to T”. After producing the list of parameter types, any
top-level cv-qualifiers modifying a parameter type are deleted when
forming the function type. The resulting list of transformed parameter
types and the presence or absence of the ellipsis or a function
parameter pack is the function’s parameter-type-list.
Basically, it means, that const int and int are interchangeable in the context of your question.
On the other hand, if you add a reference, like const int&, const is not a top level cv-qualifier anymore (it marks the referenced value as const), so the compiler complains.
Usually, const is added to the definition in order to emphasise that the parameter is not changed inside the function body.
The function declaration
void f(const T arg);
is same as
void f(T arg);
However,
void f(const T& arg);
is not the same as
void f(T& arg);
and
void f(const T* arg);
is not the same as
void f(T* arg);
void f(const T arg);
void f(T arg);
are same because top-level cv-qualifiers are removed for function resolution purposes. There, the const-ness is applied to the top-level type, T.
OTOH,
void f(const T& arg);
void f(T& arg);
are not same since the const-ness is applied to the object being referred to by the reference arg, not to arg itself which is just a top-level thing.
#include <iostream>
struct A {};
struct B : public A {};
template<typename T>
void foo(const T &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
int main()
{
foo(A());
foo(B());
return 0;
}
This prints:
Called A
Called template
I was under the impression that a suitable non-template function would always be chosen over a template function. Can someone explain to me the resolution steps that lead to this somewhat surprising result?
I was under the impression that a suitable non-template function would always be chosen over a template function.
This only holds if the template and the non-template are equally good candidates. That's why the non-template is chosen for foo(A()).
However, in the case of foo(B()), using the non-template requires a derived-to-base conversion. So the function template is strictly better, and hence it's chosen.
The foo template instantiates into void foo(const B&). Consider what it would look like without templates:
void foo(const B &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
I believe you'll agree calling foo(B()) should unambiguously pick the first one. That's exactly why the template is chosen.
n3376 13.3.3.1/6
When the parameter has a class type and the argument expression has a
derived class type, the implicit conversion sequence is a
derived-to-base Conversion from the derived class to the base class.
n3376 13.3.3.1/8
If no conversions are required to match an argument to a parameter
type, the implicit conversion sequence is the standard conversion
sequence consisting of the identity conversion (13.3.3.1.1).
Identity conversion has exact match rank due table in 13.3.3.1.1/table 12, but derived-to-base is worse, than identity.
So, compiler just have candidates in first case
// template after resolving
void foo(const A&)
// non-template
void foo(const A&)
Both has identity rank, but since first is function-template, second will be chosen.
And in second case
// template after resolving
void foo(const B&)
// non-template
void foo(const A&)
Only first has identity rank and will be chosen.
Can someone explain to me the resolution steps that lead to this somewhat surprising result?
you may look at Overload Resolution at cppreference.com:
http://en.cppreference.com/w/cpp/language/overload_resolution
in particular see the section Ranking of implicit conversion sequences
Extension of the Answer:
I tried to provide more clarification with an excerpt of the information from the aforementioned link:
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
For that, the compiler goes through:
function template name lookup
template argument deduction
Down to here, the compiler has a couple of candidate function definitions which can handle the specific function call. These candidates are instannces of the template function as well as relevant non-template function definitions in the program.
But the answer to your question lies in fact here:
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.
The fact that function overload resolution is performed after template function instantiation is the reason for the ouput of your code.
Now your specific case goes through overload resolution as the following:
Overload Resolution:
If the [previous] steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called. In general, the candidate function whose parameters match the arguments most closely is the one that is called.
.
.
.
...
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
1) there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
...
.
.
.
Ranking of implicit conversion sequences:
Each type of standard conversion sequence is assigned one of three ranks:
1) Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, user-defined conversion of class type to the same class
2) Promotion: integral promotion, floating-point promotion
3) Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds (there may be up to three conversions)
Binding of a reference parameter directly to the argument expression is either Identity or a derived-to-base Conversion:
struct Base {};
struct Derived : Base {} d;
int f(Base&); // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
// d -> Base& has rank Conversion
// calls f(Derived&)
I have a question regarding the c++ function matching for parameters of types T and const T&.
Let's say I have the following two functions:
void f(int i) {}
void f(const int &ri) {}
If I call f with an argument of type const int then this call is of course ambiguous. But why is a call of f with an argument of type int also ambiguous? Wouldn't be the first version of f be an exact match and the second one a worse match, because the int argument must be converted to a const int?
const int ci = 0;
int i = 0;
f(ci); // of course ambiguous
f(i); // why also ambiguous?
I know that such kind of overloading doesn't make much sense, because calls of f are almost always ambiguous unless the parameter type T doesn't have an accessible copy constructor. But I'm just studying the rules of function matching.
Regards,
Kevin
EDIT: To make my question more clear. If I have the two functions:
void f(int *pi) {}
void f(const int *pi) {}
Then the following call is not ambiguous:
int i = 0;
f(&i); // not ambiguous, first version f(int*) chosen
Although both versions of f could be called with &i the first version is chosen, because the second version of f would include a conversion to const. That is, the first version is a "better match". But in the two functions:
void f(int i) {} and
void f(const int &ri) {}
This additional conversion to const seems to be ignored for some reason. Again both versions of f could be called with an int. But again, the second version of f would require a conversion to const which would make it a worse match than the first version f(int).
int i = 1;
// f(int) requires no conversion
// f(const int &) does require a const conversion
// so why are both versions treated as "equally good" matches?
// isnt this analogous to the f(int*) and f(const int*) example?
f(i); // why ambiguous this time?
One call involves an "lvalue-to-rvalue conversion", the other requires an identity conversion (for references) or a "qualification adjustment" (for pointers), and according to the Standard these are treated equally when it comes to overload resolution.
So, neither is better on the basis of differing conversions.
There is, however, a special rule in the Standard, section 13.3.3.2, that applies only if both candidates being compared take the parameter by reference.
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if ... S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
There's an identical rule for pointers.
Therefore the compiler will prefer
f(int*);
f(int&);
over
f(const int*);
f(const int&);
respectively, but there's no preference for f(int) vs f(const int) vs f(const int&), because lvalue-to-rvalue transformation and qualification adjustment are both considered "Exact Match".
Also relevant, from section 13.3.3.1.4:
When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion.
The second call f(i) is also ambiguous because void f(const int &ri) indicates that ri is a reference to i and is a constant. Meaning it says that it will not modify the original i which is passed to that function.
The choice whether to modify the passed argument or not is in the hands of the implementer of the function not the client programmer who mearly uses that function.
The reason the second call f(i) is ambiguous is because to the compiler, both functions would be acceptable. const-ness can't be used to overload functions because different const versions of functions can be used in a single cause. So in your example:
int i = 0;
fi(i);
How would the compiler know which function you intended in invoking? The const qualifier is only relevant to the function definition.
See const function overloading for a more detailed explanation.
If I compile (gcc 4.6.0) and run this code:
#include <iostream>
template <typename T> void F(/* const */ T& value) {
std::cout << "T & " << value << std::endl;
}
template <typename T> void F(/* const */ T* value) {
std::cout << "T * " << value << std::endl;
F(*value);
}
int main(int argc, char* argv[]) {
float f = 123.456;
float* pf = &f;
F(pf);
return 0;
}
I get the following output:
T * 0x7fff7b2652c4
T & 123.456
If I uncomment the const keywords I get the following output:
T & 0x7fff3162c68c
I can change float* pf = &f; to const float* pf = &f; to get the original output again, that's not the issue.
What I'd like to understand is why, when compiling with the const modifiers, overload resolution considers const T& value a better match than const T* valuefor a non-const float*?
During overload resolution, overloads requiring no conversions beat overloads requiring some conversions, even if those conversions are trivial. Quoting the C++03 standard, [over.match.best] (§13.3.3/1):
Define ICSi(F) as follows:
if F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,
let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.
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,
F1 is a non-template function and F2 is a function template specialization, or, if not that,
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.5.2, 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.
When const is present, in order to call the overload taking a reference, no conversion is necessary -- T is deduced to be float* and the argument is float* const&. However, in order to call the overload taking a pointer, float would need to be converted to float const for said overload to be viable. Consequently, the overload taking a reference wins.
Note, of course, that if pf were changed to be a float const*, the behavior would go back to the way you expected because the overload taking a pointer would no longer require a conversion.