clang 3.3和constexpr约束

时间:2013-08-27 15:04:46

标签: c++ templates c++11 clang

我正在用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的规范方面,我是否违反了一些规则?此外,对于最后一个错误 - 掩码类型是无符号的 - 这是一个编译器问题,它认为我正在转移负值或我误读代码?

1 个答案:

答案 0 :(得分:3)

在第一种情况下,您导致签名溢出。在C ++ 11 5.19 / 2中列出的表达式是一个常量表达式的条件之一是它涉及

  

未在数学上定义的结果或不在其类型

的可表示值范围内的结果

通过使用无符号类型(定义为使用模运算),结果保持在范围内。据推测,GCC对此规则的严格程度不如Clang。

在最后一种情况下,无符号8位类型被提升为int,而不是无符号类型,因此您再次获得有符号溢出。你可以通过在否定之后转换回无符号类型来解决这个问题:

static constexpr mask_type frac_mask = ~(mask_type(~mask_type(0)) << F);

虽然我对此不太确定,并且没有要测试的Clang安装。