So I gave this program to g++ and clang (both on Linux, x86_64):
#include <iostream>
using namespace std;
template<char... Cs>
struct A {
static const string s;
static A a;
~A() {
cout << "s = " << s << "\n";
}
};
template<char... Cs>
const string A<Cs...>::s = {{Cs...}};
template<char... Cs>
A<Cs...> A<Cs...>::a;
int main(void)
{
(void)A<'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'>::a;
return 0;
}
Clang outputs s = aaaaaaaaaaaaaaaa
(as expected).
g++ (versions 5 until 8) outputs s = s = aaaaaaaa
(pretty unexpected).
This doesn't happen if you don't use the variadic template (if you remove all the <> code and inline the character list to initialize A::s
.
It also doesn't happen if you replace the std::string
by a character array (and use A<Cs...>::s = {Cs...}
instead).
Is this code not meant to be, or is it a compiler bug?
Your code is incorrect. The important part of the standard is 6.6.3/1 [basic.start.dynamic] in N4659:
Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization [...]
Because the initialization is not ordered, you cannot rely on the order of destruction. Any order is legal, regardless of order of construction. See 6.6.4/3 [basic.start.term]
gcc is thus allowed to destroy s
before it destroys a
, which is what happens and causes the weird output. Live .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.