use*_*897 5 c++ templates clang c++11
我正在用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);
};
Run Code Online (Sandbox Code Playgroud)
在clang中,如果我尝试声明test <16,16>或test <8,0>,我会收到错误:
test.cpp:41:34:错误:constexpr变量'frac_mask'必须由常量表达式初始化
Run Code Online (Sandbox Code Playgroud)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);
};
Run Code Online (Sandbox Code Playgroud)
它在大多数情况下编译(I,F的值),但是如果我声明test <8,0>,我得到错误:
test.cpp:23:36:错误:constexpr变量'frac_mask'必须由常量表达式初始化
test.cpp:66:15:注意:在这里请求模板类'test <8,0>'的实例化
test.cpp:23:66:注意:左移-1的负值
Run Code Online (Sandbox Code Playgroud)static constexpr mask_type frac_mask = ~((~mask_type(0)) << F);
我的问题是 - 在constexpr的规范方面,我是否违反了一些规则?此外,对于最后一个错误 - 掩码类型是无符号的 - 这是一个编译器问题,它认为我正在转移负值或我误读代码?
在第一种情况下,您会导致签名溢出。C++11 5.19/2 中列出的表达式不是常量表达式的条件之一是它涉及
未以数学方式定义或不在其类型的可表示值范围内的结果
通过使用定义为使用模算术的无符号类型,结果保持在范围内。据推测,GCC 对这条规则的严格程度不如 Clang。
在最后一种情况下,无符号 8 位类型被提升为int,而不是无符号类型,因此您会再次遇到有符号溢出。您可以通过在求反后转换回无符号类型来解决此问题:
static constexpr mask_type frac_mask = ~(mask_type(~mask_type(0)) << F);
Run Code Online (Sandbox Code Playgroud)
尽管我对此不太确定,并且没有可用于测试的 Clang 安装。
| 归档时间: |
|
| 查看次数: |
990 次 |
| 最近记录: |