问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/50339063/g-variadic-template-issue