The following code produces drastically different results when compiled with g++ or with clang++. Sorry for the long example, but I haven't been able to make it any shorter.
The program should assign a specific bit position to a specific type, then build an std::bitset
containing multiple type bits.
#include <bitset>
#include <iostream>
using namespace std;
using Bts = bitset<32>;
int getNextId() { static int last{0}; return last++; }
template<class T> struct IdStore{ static const int bitIdx; };
template<class T> const int IdStore<T>::bitIdx{getNextId()};
template<class T> void buildBtsHelper(Bts& mBts) {
mBts[IdStore<T>::bitIdx] = true;
}
template<class T1, class T2, class... A>
void buildBtsHelper(Bts& mBts) {
buildBtsHelper<T1>(mBts); buildBtsHelper<T2, A...>(mBts);
}
template<class... A> Bts getBuildBts() {
Bts result; buildBtsHelper<A...>(result); return result;
}
template<class... A> struct BtsStore{ static const Bts bts; };
template<class... A> const Bts BtsStore<A...>::bts{getBuildBts<A...>()};
template<> const Bts BtsStore<>::bts{};
template<class... A> const Bts& getBtsStore() {
return BtsStore<A...>::bts;
}
struct Type1 { int k; };
struct Type2 { float f; };
struct Type3 { double z; };
struct Type4 { };
int main()
{
cout << getBtsStore<Type1, Type2, Type3, Type4>() << endl;
return 0;
}
00000000000000000000000000000001
00000000000000000000000000001111
(as expected)
Only compilation flag is -std=c++11
.
What is happening? Am I introducing undefined behavior? Is g++ wrong?
Your code relies on initialization order of two declarations:
template<class T> const int IdStore<T>::bitIdx{getNextId()};
template<class... A> const Bts BtsStore<A...>::bts{getBuildBts<A...>()};
// getBuildBts uses IdStore<T>::bitIdx as indexes to assign
If all of IdStore<T>::bitIdx
initializations happen before BtsStore<A...>::bts
then you get your expected behavior. If all of the happen after BtsStore<A...>::bts
then you get g++ behavior. Both orderings are allowed by standard:
3.6.2 Initialization of non-local variables
2 (...) Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization.
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