I'm trying to understand some recursive C++ template code I've been handed, and I'm hitting some strange behavior. For some reason, the compiler seems able to add two values at compile-time but doing a left-shift has to be left for run-time. And even then, the problem only occurs if I try to build with c++11 enabled.
The code (which I've boiled down and you will see later) defines two pairs of templates - one pair named shft
and shft_aux
and one pair named add
and add_aux
that generate themselves recursively. BTW, the add
template is not supposed to be useful, its sole purpose is to demonstrate the problem, not to generate an actual min
value.
If I compile this code with no command-line parameters, it compiles just fine. But if I specify -std=c++11 -stdlib=libc++
, the static_assert on add_aux is still fine but the static_assert on shft_aux now generates a compile-time error saying static_assert expression is not an integral constant expression
.
Why is left-shift treated differently from addition?
Thanks, Chris
p.s. I'm using clang++ version Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
#include <climits>
template <unsigned size> struct shft; // forward
template <unsigned size>
struct shft_aux
{
static const int min = shft<size>::min;
};
template <unsigned size>
struct shft
{
typedef shft_aux<size - 1> prev;
static const int min = prev::min << CHAR_BIT;
};
// Base specialization of shft, puts an end to the recursion.
template <>
struct shft<1>
{
static const int min = SCHAR_MIN;
};
// -----
template <unsigned size> struct add; // forward
template <unsigned size>
struct add_aux
{
static const int min = add<size>::min;
};
template <unsigned size>
struct add
{
typedef add_aux<size - 1> prev;
static const int min = prev::min + CHAR_BIT;
};
// Base specialization of add, puts an end to the recursion.
template <>
struct add<1>
{
static const int min = SCHAR_MIN;
};
// -----
int main()
{
static_assert(shft_aux<sizeof(int)>::min < 0, "min is not negative");
static_assert(add_aux<sizeof(int)>::min < 0, "min is not negative");
return 0;
}