g++ and clang++ different behaviour with recursive initialization of a static member
Given the following code:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
where the static member value
of the template struct foo
is recursively initialized, I get different outputs from g++:
3 2 1 0
and from clang++:
1 1 1 0
So seem that g++ initializes foo<N>::value
recursively using the initialized value of foo<N-1u>::value
where clang++ uses zero for foo<N-1u>::value
.
Two questions:
- is the preceding code legit or is it Undefined Behavior in some way?
- if the preceding code is legit, who's right: g++ or clang++?
c++ templates recursion language-lawyer static-members
add a comment |
Given the following code:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
where the static member value
of the template struct foo
is recursively initialized, I get different outputs from g++:
3 2 1 0
and from clang++:
1 1 1 0
So seem that g++ initializes foo<N>::value
recursively using the initialized value of foo<N-1u>::value
where clang++ uses zero for foo<N-1u>::value
.
Two questions:
- is the preceding code legit or is it Undefined Behavior in some way?
- if the preceding code is legit, who's right: g++ or clang++?
c++ templates recursion language-lawyer static-members
add a comment |
Given the following code:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
where the static member value
of the template struct foo
is recursively initialized, I get different outputs from g++:
3 2 1 0
and from clang++:
1 1 1 0
So seem that g++ initializes foo<N>::value
recursively using the initialized value of foo<N-1u>::value
where clang++ uses zero for foo<N-1u>::value
.
Two questions:
- is the preceding code legit or is it Undefined Behavior in some way?
- if the preceding code is legit, who's right: g++ or clang++?
c++ templates recursion language-lawyer static-members
Given the following code:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
where the static member value
of the template struct foo
is recursively initialized, I get different outputs from g++:
3 2 1 0
and from clang++:
1 1 1 0
So seem that g++ initializes foo<N>::value
recursively using the initialized value of foo<N-1u>::value
where clang++ uses zero for foo<N-1u>::value
.
Two questions:
- is the preceding code legit or is it Undefined Behavior in some way?
- if the preceding code is legit, who's right: g++ or clang++?
c++ templates recursion language-lawyer static-members
c++ templates recursion language-lawyer static-members
edited 8 hours ago
Toby Speight
16.9k134266
16.9k134266
asked 12 hours ago
max66max66
37.4k74269
37.4k74269
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
For all other non-local static and thread-local variables, Zero initialization takes place
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following
situations:
1) Unordered dynamic initialization, which applies only to
(static/thread-local) class template static data members and ... that aren't explicitly specialized.
And these variables match the criteria. And then it says:
Initialization of such static variables is indeterminately sequenced
with respect to all other dynamic initialization ....
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use constexpr
to force a "constant initialization" instead.
add a comment |
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying int i = i-1
. In clang case, it is just using the generic template definition
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
because it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
5
"construct where you reference a variable onto itself" I disagree.foo<N>::value
andfoo<N-1>::value
are different variables.
– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
foo(N)
andfoo(N-1)
are the same, butfoo<N>()
andfoo<N-1>()
would be different.
– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,foo<3>
foo<2>
andfoo<1>
are different types, just likefoo_3
,foo_2
andfoo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates intofoo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)
– R.M.
4 hours ago
|
show 1 more 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
});
}
});
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%2f54981973%2fg-and-clang-different-behaviour-with-recursive-initialization-of-a-static-me%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
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
For all other non-local static and thread-local variables, Zero initialization takes place
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following
situations:
1) Unordered dynamic initialization, which applies only to
(static/thread-local) class template static data members and ... that aren't explicitly specialized.
And these variables match the criteria. And then it says:
Initialization of such static variables is indeterminately sequenced
with respect to all other dynamic initialization ....
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use constexpr
to force a "constant initialization" instead.
add a comment |
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
For all other non-local static and thread-local variables, Zero initialization takes place
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following
situations:
1) Unordered dynamic initialization, which applies only to
(static/thread-local) class template static data members and ... that aren't explicitly specialized.
And these variables match the criteria. And then it says:
Initialization of such static variables is indeterminately sequenced
with respect to all other dynamic initialization ....
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use constexpr
to force a "constant initialization" instead.
add a comment |
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
For all other non-local static and thread-local variables, Zero initialization takes place
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following
situations:
1) Unordered dynamic initialization, which applies only to
(static/thread-local) class template static data members and ... that aren't explicitly specialized.
And these variables match the criteria. And then it says:
Initialization of such static variables is indeterminately sequenced
with respect to all other dynamic initialization ....
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use constexpr
to force a "constant initialization" instead.
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
For all other non-local static and thread-local variables, Zero initialization takes place
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following
situations:
1) Unordered dynamic initialization, which applies only to
(static/thread-local) class template static data members and ... that aren't explicitly specialized.
And these variables match the criteria. And then it says:
Initialization of such static variables is indeterminately sequenced
with respect to all other dynamic initialization ....
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use constexpr
to force a "constant initialization" instead.
answered 12 hours ago
Michael VekslerMichael Veksler
3,6471519
3,6471519
add a comment |
add a comment |
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying int i = i-1
. In clang case, it is just using the generic template definition
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
because it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
5
"construct where you reference a variable onto itself" I disagree.foo<N>::value
andfoo<N-1>::value
are different variables.
– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
foo(N)
andfoo(N-1)
are the same, butfoo<N>()
andfoo<N-1>()
would be different.
– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,foo<3>
foo<2>
andfoo<1>
are different types, just likefoo_3
,foo_2
andfoo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates intofoo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)
– R.M.
4 hours ago
|
show 1 more comment
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying int i = i-1
. In clang case, it is just using the generic template definition
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
because it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
5
"construct where you reference a variable onto itself" I disagree.foo<N>::value
andfoo<N-1>::value
are different variables.
– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
foo(N)
andfoo(N-1)
are the same, butfoo<N>()
andfoo<N-1>()
would be different.
– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,foo<3>
foo<2>
andfoo<1>
are different types, just likefoo_3
,foo_2
andfoo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates intofoo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)
– R.M.
4 hours ago
|
show 1 more comment
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying int i = i-1
. In clang case, it is just using the generic template definition
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
because it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying int i = i-1
. In clang case, it is just using the generic template definition
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
because it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
edited 10 hours ago
answered 12 hours ago
darunedarune
1,513516
1,513516
5
"construct where you reference a variable onto itself" I disagree.foo<N>::value
andfoo<N-1>::value
are different variables.
– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
foo(N)
andfoo(N-1)
are the same, butfoo<N>()
andfoo<N-1>()
would be different.
– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,foo<3>
foo<2>
andfoo<1>
are different types, just likefoo_3
,foo_2
andfoo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates intofoo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)
– R.M.
4 hours ago
|
show 1 more comment
5
"construct where you reference a variable onto itself" I disagree.foo<N>::value
andfoo<N-1>::value
are different variables.
– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
foo(N)
andfoo(N-1)
are the same, butfoo<N>()
andfoo<N-1>()
would be different.
– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,foo<3>
foo<2>
andfoo<1>
are different types, just likefoo_3
,foo_2
andfoo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates intofoo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)
– R.M.
4 hours ago
5
5
"construct where you reference a variable onto itself" I disagree.
foo<N>::value
and foo<N-1>::value
are different variables.– HolyBlackCat
12 hours ago
"construct where you reference a variable onto itself" I disagree.
foo<N>::value
and foo<N-1>::value
are different variables.– HolyBlackCat
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
Compare it to a function taking one argument - are foo(N) and foo(N-1) two different functions ?
– darune
12 hours ago
6
6
foo(N)
and foo(N-1)
are the same, but foo<N>()
and foo<N-1>()
would be different.– HolyBlackCat
12 hours ago
foo(N)
and foo(N-1)
are the same, but foo<N>()
and foo<N-1>()
would be different.– HolyBlackCat
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
Which is why I wrote "a construct" - feel free to clarify my answer though - I know it wasn't the greatest for 'correctness'
– darune
12 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,
foo<3>
foo<2>
and foo<1>
are different types, just like foo_3
, foo_2
and foo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates into foo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)– R.M.
4 hours ago
@darune The issue with the answer is that "itself"-ness doesn't really come into it. Absent any phrasing for specific case in the standard which says otherwise,
foo<3>
foo<2>
and foo<1>
are different types, just like foo_3
, foo_2
and foo_1
would be. As I understand it, the template is a bit of a red herring: you'd (theoretically) have exactly the same sort of issues if you manually unrolled the templates into foo_3
, etc. (On a standards level, at least - the compilers might treat them differently.)– R.M.
4 hours ago
|
show 1 more comment
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%2f54981973%2fg-and-clang-different-behaviour-with-recursive-initialization-of-a-static-me%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