[英]g++ and clang different behavior with recursive variadic template bitset creation (possible gcc bug?)
使用g ++或clang ++编译时,以下代码会产生截然不同的结果。 很抱歉这个很长的例子,但我还没能做到更短。
程序应将特定位位置分配给特定类型,然后构建包含多个类型位的std::bitset
。
#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
(正如预期的那样) 只有编译标志是-std=c++11
。
怎么了? 我是否引入了未定义的行为? g ++错了吗?
您的代码依赖于两个声明的初始化顺序:
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
如果所有IdStore<T>::bitIdx
初始化都发生在BtsStore<A...>::bts
那么您将获得预期的行为。 如果所有这些都发生在BtsStore<A...>::bts
之后,那么你会得到g ++行为。 标准允许两种排序:
3.6.2非局部变量的初始化
2(...)具有静态存储持续时间的非局部变量的动态初始化是有序的或无序的。 显式专用类模板的定义静态数据成员已经有序初始化。 其他类模板静态数据成员(即,隐式或显式实例化的特化)具有无序初始化 。
解决方案是使IdStore::bitIdx
成为静态成员函数,返回静态局部变量。
添加到zch的答案 。
在定义了这些类型之后,强制对Type1
, Type2
, Type3
和Type4
强制执行IdStore
的实例, 似乎解决了这个问题。 为此,在Type1
, Type2
, Type3
和Type4
的定义之后添加这些行。
template struct IdStore<Type1>;
template struct IdStore<Type2>;
template struct IdStore<Type3>;
template struct IdStore<Type4>;
更新 :像维托里奥一样,我不再喜欢上面的解决方案了。 这是另一个。 将IdStore
转换为模板函数:
template <typename T>
int IdStore() {
return getNextId();
}
并且,在buildBtsHelper
使用它:
mBts[IdStore<T>()] = true;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.