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?
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.
Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.
Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With