我正在用clang 3.3编译一些代码,似乎可以用gcc 4.8编译好:
原始代码是:
template <std::size_t N> struct helper { typedef void type; };
template <> struct helper<64> { typedef int64_t type; };
template <> struct helper<32> { typedef int32_t type; };
template <> struct helper<16> { typedef int16_t type; };
template <> struct helper<8> { typedef int8_t type; };
template <std::size_t I, std::size_t F>
struct test
{
typedef typename helper<I+F>::type value_type;
static constexpr std::size_t frac_mask = ~((~value_type(0)) << F);
};
在clang中,如果我尝试声明测试&lt; 16,16&gt;或测试&lt; 8,0&gt;我收到错误:
test.cpp:41:34:错误:constexpr变量'frac_mask'必须用常量表达式初始化
static constexpr std::size_t frac_mask = ~((~value_type(0)) << F);
如果我将代码转换为:
,请使用它template <std::size_t I, std::size_t F>
struct test
{
typedef typename helper<I+F>::type value_type;
typedef typename std::make_unsigned<value_type>::type mask_type;
static constexpr mask_type frac_mask = ~((~mask_type(0)) << F);
};
它在大多数情况下编译(I,F的值),但是如果我声明测试&lt; 8,0&gt;,我得到错误:
test.cpp:23:36:错误:constexpr变量'frac_mask'必须用常量表达式初始化
test.cpp:66:15:注意:在模板类'test&lt; 8,0&gt;'的实例化中请求
test.cpp:23:66:注意:左移-1的负值
static constexpr mask_type frac_mask = ~((~mask_type(0)) << F);
我的问题是 - 在constexpr的规范方面,我是否违反了一些规则?此外,对于最后一个错误 - 掩码类型是无符号的 - 这是一个编译器问题,它认为我正在转移负值或我误读代码?
答案 0 :(得分:3)
在第一种情况下,您导致签名溢出。在C ++ 11 5.19 / 2中列出的表达式不是一个常量表达式的条件之一是它涉及
未在数学上定义的结果或不在其类型
的可表示值范围内的结果
通过使用无符号类型(定义为使用模运算),结果保持在范围内。据推测,GCC对此规则的严格程度不如Clang。
在最后一种情况下,无符号8位类型被提升为int
,而不是无符号类型,因此您再次获得有符号溢出。你可以通过在否定之后转换回无符号类型来解决这个问题:
static constexpr mask_type frac_mask = ~(mask_type(~mask_type(0)) << F);
虽然我对此不太确定,并且没有要测试的Clang安装。