简体   繁体   English

使用递归可变参数模板bitset创建g ++和clang不同的行为(可能的gcc bug?)

[英]g++ and clang different behavior with recursive variadic template bitset creation (possible gcc bug?)

The following code produces drastically different results when compiled with g++ or with clang++ . 使用g ++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. 程序应将特定位位置分配给特定类型,然后构建包含多个类型位的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;
}
  • g++ 4.8.2 prints-----: 00000000000000000000000000000001 g ++ 4.8.2打印-----: 00000000000000000000000000000001
  • clang++ SVN prints: 00000000000000000000000000001111 (as expected) clang ++ SVN打印: 00000000000000000000000000001111 (正如预期的那样)

Only compilation flag is -std=c++11 . 只有编译标志是-std=c++11

What is happening? 怎么了? Am I introducing undefined behavior? 我是否引入了未定义的行为? Is g++ wrong? g ++错了吗?

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. 如果所有IdStore<T>::bitIdx初始化都发生在BtsStore<A...>::bts那么您将获得预期的行为。 If all of the happen after BtsStore<A...>::bts then you get g++ behavior. 如果所有这些都发生在BtsStore<A...>::bts之后,那么你会得到g ++行为。 Both orderings are allowed by standard: 标准允许两种排序:

3.6.2 Initialization of non-local variables 3.6.2非局部变量的初始化

2 (...) Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. 2(...)具有静态存储持续时间的非局部变量的动态初始化是有序的或无序的。 Definitions of explicitly specialized class template static data members have ordered initialization. 显式专用类模板的定义静态数据成员已经有序初始化。 Other class template static data members (ie, implicitly or explicitly instantiated specializations) have unordered initialization . 其他类模板静态数据成员(即,隐式或显式实例化的特化)具有无序初始化

解决方案是使IdStore::bitIdx成为静态成员函数,返回静态局部变量。

Adding to zch's answer . 添加到zch的答案

Forcing the instatiations of IdStore for Type1 , Type2 , Type3 and Type4 just after these types are defined, seems to fix the problem. 在定义了这些类型之后,强制对Type1Type2Type3Type4强制执行IdStore的实例, 似乎解决了这个问题。 For this, add these lines just after the definitions of Type1 , Type2 , Type3 and Type4 . 为此,在Type1Type2Type3Type4的定义之后添加这些行。

template struct IdStore<Type1>;
template struct IdStore<Type2>;
template struct IdStore<Type3>;
template struct IdStore<Type4>;

Update : Like Vittorio, I no longer like the solution above. 更新 :像维托里奥一样,我不再喜欢上面的解决方案了。 Here is another one. 这是另一个。 Turn IdStore into a template function: IdStore转换为模板函数:

template <typename T>
int IdStore() {
    return getNextId();
}

and, in buildBtsHelper use it this way: 并且,在buildBtsHelper使用它:

mBts[IdStore<T>()] = true;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 可变参数模板元编程:clang ++或g ++中的错误? - Variadic template metaprogramming : a bug in clang++ or g++? g ++和clang ++使用指向可变参数模板函数的指针的不同行为 - g++ and clang++ different behaviour with pointer to variadic template functions Clang和GCC在解析可变参数函数模板时的不同行为 - Clang and GCC different behavior when resolving variadic function template overload g ++和clang ++不同的行为推导可变参数模板`auto`值 - g++ and clang++ different behaviour deducing variadic template `auto` values 空包装的Functor可变参数模板包装扩展在clang ++和g ++中给出了不同的结果 - Functor variadic template pack expansion for empty pack gives different results in clang++ and g++ 使用lambdas的变量模板:使用g ++但使用clang ++运行时出错 - Variadic template using lambdas : error with g++ but running with clang++ 奇怪的模板编译错误:这是 g++ 错误、Clang 错误还是...? - Strange template compile errors: is this a g++ bug, a Clang bug, or...? g++ 和 clang++ 与可变参数容器的不同行为 - g++ and clang++ different behaviour with variadic container 这是 g++ 或 clang++ 中的错误 - Is this a bug in g++ or clang++ g ++可变参数模板问题 - g++ variadic template issue
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM