Why do type traits not work with types in namespace scope?What are POD types in C++?Why can templates only be...
What does it mean to express a gate in Dirac notation?
A Strange Latex Symbol
How can Republicans who favour free markets, consistently express anger when they don't like the outcome of that choice?
What happened to Captain America in Endgame?
How to solve constants out of the internal energy equation?
How can I place the product on a social media post better?
Will tsunami waves travel forever if there was no land?
Unexpected email from Yorkshire Bank
What is the relationship between spectral sequences and obstruction theory?
How can I practically buy stocks?
Will a top journal at least read my introduction?
Examples of non trivial equivalence relations , I mean equivalence relations without the expression " same ... as" in their definition?
Was there a Viking Exchange as well as a Columbian one?
Why does processed meat contain preservatives, while canned fish needs not?
What language was spoken in East Asia before Proto-Turkic?
Contradiction proof for inequality of P and NP?
What does the "ep" capability mean?
Shrinkwrap tetris shapes without scaling or diagonal shapes
Rivers without rain
Realistic Necromancy?
Is contacting this expert in the field something acceptable or would it be discourteous?
Combinable filters
Can someone publish a story that happened to you?
Fizzy, soft, pop and still drinks
Why do type traits not work with types in namespace scope?
What are POD types in C++?Why can templates only be implemented in the header file?Why is “using namespace std” considered bad practice?Why do we need virtual functions in C++?Can a local variable's memory be accessed outside its scope?Why are elementwise additions much faster in separate loops than in a combined loop?Why does changing 0.1f to 0 slow down performance by 10x?Why is reading lines from stdin much slower in C++ than Python?Why is it faster to process a sorted array than an unsorted array?Why should I use a pointer rather than the object itself?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I'm designing a type register feature for my C++ serializing library.
But I encountered a strange problem about type traits.
I'm using Visual Studio 2017 with /std:c++latest.
#include <type_traits>
int reg(...);
template<class T>
constexpr bool is_known = !std::is_same_v<decltype(reg((T*)1)), int>;
//----- for type1 in global scope ------
struct type1 {};
void reg(type1 *);
static_assert(is_known<type1>); // success
//----- for type2 in namespace scope ----
namespace ns { struct type2 { }; }
void reg(ns::type2 *);
static_assert(is_known<ns::type2>); // fail!!!!
Static assert succeeds for type1, which is in global scope, but fails for namespace scope type2.
Why is there a difference?
c++
New contributor
add a comment |
I'm designing a type register feature for my C++ serializing library.
But I encountered a strange problem about type traits.
I'm using Visual Studio 2017 with /std:c++latest.
#include <type_traits>
int reg(...);
template<class T>
constexpr bool is_known = !std::is_same_v<decltype(reg((T*)1)), int>;
//----- for type1 in global scope ------
struct type1 {};
void reg(type1 *);
static_assert(is_known<type1>); // success
//----- for type2 in namespace scope ----
namespace ns { struct type2 { }; }
void reg(ns::type2 *);
static_assert(is_known<ns::type2>); // fail!!!!
Static assert succeeds for type1, which is in global scope, but fails for namespace scope type2.
Why is there a difference?
c++
New contributor
add a comment |
I'm designing a type register feature for my C++ serializing library.
But I encountered a strange problem about type traits.
I'm using Visual Studio 2017 with /std:c++latest.
#include <type_traits>
int reg(...);
template<class T>
constexpr bool is_known = !std::is_same_v<decltype(reg((T*)1)), int>;
//----- for type1 in global scope ------
struct type1 {};
void reg(type1 *);
static_assert(is_known<type1>); // success
//----- for type2 in namespace scope ----
namespace ns { struct type2 { }; }
void reg(ns::type2 *);
static_assert(is_known<ns::type2>); // fail!!!!
Static assert succeeds for type1, which is in global scope, but fails for namespace scope type2.
Why is there a difference?
c++
New contributor
I'm designing a type register feature for my C++ serializing library.
But I encountered a strange problem about type traits.
I'm using Visual Studio 2017 with /std:c++latest.
#include <type_traits>
int reg(...);
template<class T>
constexpr bool is_known = !std::is_same_v<decltype(reg((T*)1)), int>;
//----- for type1 in global scope ------
struct type1 {};
void reg(type1 *);
static_assert(is_known<type1>); // success
//----- for type2 in namespace scope ----
namespace ns { struct type2 { }; }
void reg(ns::type2 *);
static_assert(is_known<ns::type2>); // fail!!!!
Static assert succeeds for type1, which is in global scope, but fails for namespace scope type2.
Why is there a difference?
c++
c++
New contributor
New contributor
edited 14 hours ago
Boann
37.7k1291123
37.7k1291123
New contributor
asked 20 hours ago
shawn5013shawn5013
411
411
New contributor
New contributor
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg
depends on T
because the argument type T*
depends on T
.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg
is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known
is defined before the following overloads of reg
, unqualified lookup may only find reg(...)
. Since reg(ns::type2*)
isn't within the associated namespace of ns::type2
, it isn't found by ADL either.
add a comment |
There are two sets of places examined when the lookup of reg((T*))
is done to find which reg
is being referred to. The first is where the template is declared (where int reg(...)
is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2*
does not examine the global namespace. It examines namespaces associated with that type, namely ns
in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1
does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg
into the namespace of ns::type2
, or otherwise ensure that the namespace you define reg
in is associated with the argument to reg
(like use tag templates instead of pointers), or define reg
before you define its use in decltype
. Or something fancier; without underlying problem description I cannot guess.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
shawn5013 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
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55878310%2fwhy-do-type-traits-not-work-with-types-in-namespace-scope%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg
depends on T
because the argument type T*
depends on T
.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg
is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known
is defined before the following overloads of reg
, unqualified lookup may only find reg(...)
. Since reg(ns::type2*)
isn't within the associated namespace of ns::type2
, it isn't found by ADL either.
add a comment |
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg
depends on T
because the argument type T*
depends on T
.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg
is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known
is defined before the following overloads of reg
, unqualified lookup may only find reg(...)
. Since reg(ns::type2*)
isn't within the associated namespace of ns::type2
, it isn't found by ADL either.
add a comment |
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg
depends on T
because the argument type T*
depends on T
.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg
is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known
is defined before the following overloads of reg
, unqualified lookup may only find reg(...)
. Since reg(ns::type2*)
isn't within the associated namespace of ns::type2
, it isn't found by ADL either.
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg
depends on T
because the argument type T*
depends on T
.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg
is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known
is defined before the following overloads of reg
, unqualified lookup may only find reg(...)
. Since reg(ns::type2*)
isn't within the associated namespace of ns::type2
, it isn't found by ADL either.
edited 6 hours ago
answered 18 hours ago
Passer ByPasser By
10.5k42662
10.5k42662
add a comment |
add a comment |
There are two sets of places examined when the lookup of reg((T*))
is done to find which reg
is being referred to. The first is where the template is declared (where int reg(...)
is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2*
does not examine the global namespace. It examines namespaces associated with that type, namely ns
in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1
does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg
into the namespace of ns::type2
, or otherwise ensure that the namespace you define reg
in is associated with the argument to reg
(like use tag templates instead of pointers), or define reg
before you define its use in decltype
. Or something fancier; without underlying problem description I cannot guess.
add a comment |
There are two sets of places examined when the lookup of reg((T*))
is done to find which reg
is being referred to. The first is where the template is declared (where int reg(...)
is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2*
does not examine the global namespace. It examines namespaces associated with that type, namely ns
in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1
does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg
into the namespace of ns::type2
, or otherwise ensure that the namespace you define reg
in is associated with the argument to reg
(like use tag templates instead of pointers), or define reg
before you define its use in decltype
. Or something fancier; without underlying problem description I cannot guess.
add a comment |
There are two sets of places examined when the lookup of reg((T*))
is done to find which reg
is being referred to. The first is where the template is declared (where int reg(...)
is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2*
does not examine the global namespace. It examines namespaces associated with that type, namely ns
in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1
does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg
into the namespace of ns::type2
, or otherwise ensure that the namespace you define reg
in is associated with the argument to reg
(like use tag templates instead of pointers), or define reg
before you define its use in decltype
. Or something fancier; without underlying problem description I cannot guess.
There are two sets of places examined when the lookup of reg((T*))
is done to find which reg
is being referred to. The first is where the template is declared (where int reg(...)
is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2*
does not examine the global namespace. It examines namespaces associated with that type, namely ns
in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1
does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg
into the namespace of ns::type2
, or otherwise ensure that the namespace you define reg
in is associated with the argument to reg
(like use tag templates instead of pointers), or define reg
before you define its use in decltype
. Or something fancier; without underlying problem description I cannot guess.
edited 14 hours ago
Alan Birtles
10.1k11235
10.1k11235
answered 18 hours ago
Yakk - Adam NevraumontYakk - Adam Nevraumont
190k21200386
190k21200386
add a comment |
add a comment |
shawn5013 is a new contributor. Be nice, and check out our Code of Conduct.
shawn5013 is a new contributor. Be nice, and check out our Code of Conduct.
shawn5013 is a new contributor. Be nice, and check out our Code of Conduct.
shawn5013 is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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%2f55878310%2fwhy-do-type-traits-not-work-with-types-in-namespace-scope%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