Overload resolution looking into namespaces
up vote
28
down vote
favorite
The following code fails as expected, because no overload of get
is found. Using std::get
would solve the problem.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
However, introducing a templated version of get
, even though it's not matching the function call, somehow makes the compiler use the std::get
version:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?
This behaviour was tested in
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (still an experimental version)
EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?
c++ overload-resolution
|
show 2 more comments
up vote
28
down vote
favorite
The following code fails as expected, because no overload of get
is found. Using std::get
would solve the problem.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
However, introducing a templated version of get
, even though it's not matching the function call, somehow makes the compiler use the std::get
version:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?
This behaviour was tested in
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (still an experimental version)
EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?
c++ overload-resolution
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
1
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
1
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03
|
show 2 more comments
up vote
28
down vote
favorite
up vote
28
down vote
favorite
The following code fails as expected, because no overload of get
is found. Using std::get
would solve the problem.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
However, introducing a templated version of get
, even though it's not matching the function call, somehow makes the compiler use the std::get
version:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?
This behaviour was tested in
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (still an experimental version)
EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?
c++ overload-resolution
The following code fails as expected, because no overload of get
is found. Using std::get
would solve the problem.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
However, introducing a templated version of get
, even though it's not matching the function call, somehow makes the compiler use the std::get
version:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?
This behaviour was tested in
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (still an experimental version)
EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?
c++ overload-resolution
c++ overload-resolution
edited Nov 20 at 14:03
asked Nov 20 at 12:55
LcdDrm
532411
532411
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
1
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
1
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03
|
show 2 more comments
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
1
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
1
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
1
1
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
1
1
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03
|
show 2 more comments
2 Answers
2
active
oldest
votes
up vote
18
down vote
accepted
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
Well that makes sense. Although in GCC 9.0.0, avoid get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
Good answer, but I'd mention whatget<0>(ar)
is parsed as without the template:(get<0)>(ar)
. This makes it more clear why the existence of the templateget
makes a difference.
– Yakk - Adam Nevraumont
Nov 20 at 15:47
add a comment |
up vote
4
down vote
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
18
down vote
accepted
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
Well that makes sense. Although in GCC 9.0.0, avoid get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
Good answer, but I'd mention whatget<0>(ar)
is parsed as without the template:(get<0)>(ar)
. This makes it more clear why the existence of the templateget
makes a difference.
– Yakk - Adam Nevraumont
Nov 20 at 15:47
add a comment |
up vote
18
down vote
accepted
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
Well that makes sense. Although in GCC 9.0.0, avoid get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
Good answer, but I'd mention whatget<0>(ar)
is parsed as without the template:(get<0)>(ar)
. This makes it more clear why the existence of the templateget
makes a difference.
– Yakk - Adam Nevraumont
Nov 20 at 15:47
add a comment |
up vote
18
down vote
accepted
up vote
18
down vote
accepted
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
edited Nov 21 at 19:15
answered Nov 20 at 13:14
Jans
6,14112233
6,14112233
Well that makes sense. Although in GCC 9.0.0, avoid get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
Good answer, but I'd mention whatget<0>(ar)
is parsed as without the template:(get<0)>(ar)
. This makes it more clear why the existence of the templateget
makes a difference.
– Yakk - Adam Nevraumont
Nov 20 at 15:47
add a comment |
Well that makes sense. Although in GCC 9.0.0, avoid get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
Good answer, but I'd mention whatget<0>(ar)
is parsed as without the template:(get<0)>(ar)
. This makes it more clear why the existence of the templateget
makes a difference.
– Yakk - Adam Nevraumont
Nov 20 at 15:47
Well that makes sense. Although in GCC 9.0.0, a
void get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?– LcdDrm
Nov 20 at 13:34
Well that makes sense. Although in GCC 9.0.0, a
void get();
is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?– LcdDrm
Nov 20 at 13:34
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
That version of GCC is still under development, its too early to say that
– Jans
Nov 20 at 13:46
5
5
Good answer, but I'd mention what
get<0>(ar)
is parsed as without the template: (get<0)>(ar)
. This makes it more clear why the existence of the template get
makes a difference.– Yakk - Adam Nevraumont
Nov 20 at 15:47
Good answer, but I'd mention what
get<0>(ar)
is parsed as without the template: (get<0)>(ar)
. This makes it more clear why the existence of the template get
makes a difference.– Yakk - Adam Nevraumont
Nov 20 at 15:47
add a comment |
up vote
4
down vote
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.
add a comment |
up vote
4
down vote
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.
add a comment |
up vote
4
down vote
up vote
4
down vote
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.
answered Nov 20 at 18:54
T.C.
104k13212317
104k13212317
add a comment |
add a comment |
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
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53393467%2foverload-resolution-looking-into-namespaces%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
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
Required, but never shown
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
Required, but never shown
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
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
Nov 20 at 13:11
1
I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
Nov 20 at 13:13
Alternatively, just don't give your functions names that are already within the standard library.
– jfh
Nov 20 at 16:26
1
@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
Nov 20 at 16:51
@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
Nov 20 at 17:03