启用c ++ 11时,c ++递归模板的奇怪行为

时间:2014-04-23 16:51:16

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

我正在尝试理解我已经提交的一些递归C ++模板代码,而且我遇到了一些奇怪的行为。出于某种原因,编译器似乎能够在编译时添加两个值,但是必须保留左移以用于运行时。即使这样,只有在我尝试使用c ++ 11构建时才会出现问题。

代码(我已经简化了,你稍后会看到)定义了两对模板 - 一对名为shftshft_aux,一对名为add和{{ 1}}以递归方式生成自己。顺便说一句,add_aux模板不应该有用,它的唯一目的是演示问题,而不是生成实际的add值。

如果我在没有命令行参数的情况下编译此代码,它编译就好了。但是如果我指定min,则add_aux上的static_assert仍然可以,但是shft_aux上的static_assert现在会生成一个编译时错误-std=c++11 -stdlib=libc++

为什么左移处理不同于添加?

谢谢, 克里斯

P.S。我正在使用clang ++版本static_assert expression is not an integral constant expression

Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)

1 个答案:

答案 0 :(得分:7)

C ++ 11 Standard,[expr.shift] / 2

  

E1 << E2的值为E1左移E2位位置;空位是零填充的。如果E1具有无符号类型,[...]。否则,如果E1具有有符号类型和非负值,并且 E1 * 2 E2 可表示   在结果类型中,那就是结果值; 否则,行为未定义

[强调我的]

DR1457稍微影响了这一点,这使转换为“符号位”定义的行为:

  

否则,如果E1具有有符号类型和非负值,并且 E1 * 2 E2 可在结果的相应无符号类型中表示输入[...]。

无论如何,在OP中,E1是否定的,所以仍然是未定义的行为。因此,常量表达式

中不允许使用它
  

[expr.const] / 2   条件表达式核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式[...]

     
      
  • [...]
  •   
  • 未在数学上定义的结果或不在其类型的可表示值范围内的结果;
  •   

这一点已经改变(DR1313);在n3485它说:

  
      
  • 一个具有未定义行为的操作[注意:包括,例如,有符号整数over-   流程(第5条),某些指针算术(5.7),除零(5.6)或某些移位操作(5.8)    - 结束记录];
  •   

[class.static.data] / 3

  

如果非易失性const static数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或等于初始值,其中作为赋值表达式的每个 initializer-clause 是一个常量表达式


结论:移位SCHAR_MIN不是常量表达式,因此您不能在静态数据成员的类内初始值设定项中执行此操作。

提示:始终使用-Wall -Wextra -pedantic进行编译。不使用参数IMO对于g ++和兼容的编译器来说是一个坏主意。 g ++ / clang ++默认使用gnu99模式(see clang doc),它是C ++ 98 AFAIK的扩展。此外,你会错过很多重要的警告。