Ambiguous C ++ templates?
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
I need some help in this code. I declare two templates, the first converts the argument x
from type T
to type U
and the second from type U
to type T
. If I call cast
with 10, the compiler does not throw the exception, I think both meet the requirements to be used and There should be ambiguity, is that true? This code prints 10.
#include <iostream>
template<typename T,typename U>
U cast(T x)
return static_cast<U>(x);
template<typename T,typename U>
T cast(U x)
return static_cast<T>(x);
int main(int argc, char const *argv)
std::cout << cast<int,float>(10) << "n";
return 0;
c++ templates
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
up vote
6
down vote
favorite
I need some help in this code. I declare two templates, the first converts the argument x
from type T
to type U
and the second from type U
to type T
. If I call cast
with 10, the compiler does not throw the exception, I think both meet the requirements to be used and There should be ambiguity, is that true? This code prints 10.
#include <iostream>
template<typename T,typename U>
U cast(T x)
return static_cast<U>(x);
template<typename T,typename U>
T cast(U x)
return static_cast<T>(x);
int main(int argc, char const *argv)
std::cout << cast<int,float>(10) << "n";
return 0;
c++ templates
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
If you change your code tocast<int,float>(10.0f)
the second overload would be called. And if you changed it tocast<int,float>(10.0)
the call would be ambiguous.
– Praetorian
15 mins ago
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
I need some help in this code. I declare two templates, the first converts the argument x
from type T
to type U
and the second from type U
to type T
. If I call cast
with 10, the compiler does not throw the exception, I think both meet the requirements to be used and There should be ambiguity, is that true? This code prints 10.
#include <iostream>
template<typename T,typename U>
U cast(T x)
return static_cast<U>(x);
template<typename T,typename U>
T cast(U x)
return static_cast<T>(x);
int main(int argc, char const *argv)
std::cout << cast<int,float>(10) << "n";
return 0;
c++ templates
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
I need some help in this code. I declare two templates, the first converts the argument x
from type T
to type U
and the second from type U
to type T
. If I call cast
with 10, the compiler does not throw the exception, I think both meet the requirements to be used and There should be ambiguity, is that true? This code prints 10.
#include <iostream>
template<typename T,typename U>
U cast(T x)
return static_cast<U>(x);
template<typename T,typename U>
T cast(U x)
return static_cast<T>(x);
int main(int argc, char const *argv)
std::cout << cast<int,float>(10) << "n";
return 0;
c++ templates
c++ templates
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 22 mins ago
wic
785
785
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
If you change your code tocast<int,float>(10.0f)
the second overload would be called. And if you changed it tocast<int,float>(10.0)
the call would be ambiguous.
– Praetorian
15 mins ago
add a comment |Â
If you change your code tocast<int,float>(10.0f)
the second overload would be called. And if you changed it tocast<int,float>(10.0)
the call would be ambiguous.
– Praetorian
15 mins ago
If you change your code to
cast<int,float>(10.0f)
the second overload would be called. And if you changed it to cast<int,float>(10.0)
the call would be ambiguous.– Praetorian
15 mins ago
If you change your code to
cast<int,float>(10.0f)
the second overload would be called. And if you changed it to cast<int,float>(10.0)
the call would be ambiguous.– Praetorian
15 mins ago
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
12
down vote
accepted
When you use cast<int, float>
, both templates are considered.
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
we then substitute:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
at this point, there are no types to deduce. So we go to overload resolution.
In one case, we can take an int
and convert to float
when calling cast, and in the other we take a int
and convert to int
when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.
The second non-conversion (at the point of call) is a better match, so that overload is chosen.
If you did this:
std::cout << cast<int>(10) << "n";
things get more interesting:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
for the first one, we cannot deduce U
. For the second one we can.
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
so here we have one viable overload, and it is used.
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
add a comment |Â
up vote
2
down vote
The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10
is an int
, which is also explicitly specified for the first template type.
You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
12
down vote
accepted
When you use cast<int, float>
, both templates are considered.
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
we then substitute:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
at this point, there are no types to deduce. So we go to overload resolution.
In one case, we can take an int
and convert to float
when calling cast, and in the other we take a int
and convert to int
when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.
The second non-conversion (at the point of call) is a better match, so that overload is chosen.
If you did this:
std::cout << cast<int>(10) << "n";
things get more interesting:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
for the first one, we cannot deduce U
. For the second one we can.
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
so here we have one viable overload, and it is used.
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
add a comment |Â
up vote
12
down vote
accepted
When you use cast<int, float>
, both templates are considered.
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
we then substitute:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
at this point, there are no types to deduce. So we go to overload resolution.
In one case, we can take an int
and convert to float
when calling cast, and in the other we take a int
and convert to int
when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.
The second non-conversion (at the point of call) is a better match, so that overload is chosen.
If you did this:
std::cout << cast<int>(10) << "n";
things get more interesting:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
for the first one, we cannot deduce U
. For the second one we can.
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
so here we have one viable overload, and it is used.
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
add a comment |Â
up vote
12
down vote
accepted
up vote
12
down vote
accepted
When you use cast<int, float>
, both templates are considered.
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
we then substitute:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
at this point, there are no types to deduce. So we go to overload resolution.
In one case, we can take an int
and convert to float
when calling cast, and in the other we take a int
and convert to int
when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.
The second non-conversion (at the point of call) is a better match, so that overload is chosen.
If you did this:
std::cout << cast<int>(10) << "n";
things get more interesting:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
for the first one, we cannot deduce U
. For the second one we can.
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
so here we have one viable overload, and it is used.
When you use cast<int, float>
, both templates are considered.
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
we then substitute:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
at this point, there are no types to deduce. So we go to overload resolution.
In one case, we can take an int
and convert to float
when calling cast, and in the other we take a int
and convert to int
when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.
The second non-conversion (at the point of call) is a better match, so that overload is chosen.
If you did this:
std::cout << cast<int>(10) << "n";
things get more interesting:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
for the first one, we cannot deduce U
. For the second one we can.
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
so here we have one viable overload, and it is used.
edited 7 mins ago
answered 18 mins ago
Yakk - Adam Nevraumont
172k18175354
172k18175354
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
add a comment |Â
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
– jakub_d
10 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
@jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
– Yakk - Adam Nevraumont
8 mins ago
add a comment |Â
up vote
2
down vote
The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10
is an int
, which is also explicitly specified for the first template type.
You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";
add a comment |Â
up vote
2
down vote
The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10
is an int
, which is also explicitly specified for the first template type.
You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";
add a comment |Â
up vote
2
down vote
up vote
2
down vote
The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10
is an int
, which is also explicitly specified for the first template type.
You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";
The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10
is an int
, which is also explicitly specified for the first template type.
You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";
answered 19 mins ago


lubgr
7,62521442
7,62521442
add a comment |Â
add a comment |Â
wic is a new contributor. Be nice, and check out our Code of Conduct.
wic is a new contributor. Be nice, and check out our Code of Conduct.
wic is a new contributor. Be nice, and check out our Code of Conduct.
wic is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52609797%2fambiguous-c-templates%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
If you change your code to
cast<int,float>(10.0f)
the second overload would be called. And if you changed it tocast<int,float>(10.0)
the call would be ambiguous.– Praetorian
15 mins ago