C++11 constexpr function compiler error with ternary conditional operator (?:) - c++

What is wrong with this piece of code?
#include <iostream>
template<unsigned int N, unsigned int P=0>
constexpr unsigned int Log2() {
return (N <= 1) ? P : Log2<N/2,P+1>();
}
int main()
{
std::cout << "Log2(8) = " << Log2<8>() << std::endl;
return 0;
}
When compiling with gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5), I get the following error:
log2.cpp: In function ‘constexpr unsigned int Log2() [with unsigned int N = 0u, unsigned int P = 1023u]’:
log2.cpp:5:38: error: template instantiation depth exceeds maximum of 1024 (use -ftemplate-depth= to increase the maximum) instantiating ‘constexpr unsigned int Log2() [with unsigned int N = 0u, unsigned int P = 1024u]’
log2.cpp:5:38: recursively instantiated from ‘constexpr unsigned int Log2() [with unsigned int N = 4u, unsigned int P = 1u]’
log2.cpp:5:38: instantiated from ‘constexpr unsigned int Log2() [with unsigned int N = 8u, unsigned int P = 0u]’
log2.cpp:10:37: instantiated from here

Constexpr doesn't work that way.
Simply put, constexpr functions must be available as runtime functions too. Imagine you took the constexpr off the function. Then think about why it cannot possibly work.
The reason is that the compiler has to instantiate the body of the function completely; it cannot decide based on the condition in the ?: not to instantiate one side. So it always has to instantiate the recursive call, leading to infinite recursion.
In any case, you're using constexpr wrong. You're using the old template metaprogramming calculation technique (passing stuff as template parameters) when constexpr was intended to replace this. Just use normal parameters.
constexpr unsigned Log2(unsigned n, unsigned p = 0) {
return (n <= 1) ? p : Log2(n / 2, p + 1);
}
std::cout << "Log2(8) = " << Log2(8) << std::endl;
Edit: I'll try to elaborate on how this works.
When the compiler encounters your code, it parses the template function and stores it in template form. (How this works differs between compilers.) So far, all is fine.
Next, in main, the compiler sees the call Log2<8>(). It sees that it has to instantiate the template, so it goes ahead and does exactly that: it instantiates Log2<8, 0>. The body of the function template is this:
return (N <= 1) ? P : Log2<N/2,P+1>();
OK, the compiler sees this, but it doesn't try to evaluate it. Why would it? It's currently instantiating a template, not calculating a value. It just substitutes the values supplied:
return (8 <= 1) ? 0 : Log2<8/2,0+1>();
Huh, there's another template instantiation here. It doesn't matter that it's in a conditional expression, or that the left hand side could be known. Template instantiation must be complete. So it goes ahead and calculates the values for the new instantiation and then instantiates Log2<4, 1>:
return (4 <= 1) ? 1 : Log2<4/2,1+1>();
And the game begins again. There's a template instantiation in there, and it's Log2<2, 2>:
return (2 <= 1) ? 2 : Log2<2/2,2+1>();
And again, Log2<1,3>():
return (1 <= 1) ? 3 : Log2<1/2,3+1>();
Did I mention that the compiler doesn't care about the semantic meaning of this stuff? It's just yet another template to instantiate: Log2<0,4>:
return (0 <= 1) ? 4 : Log2<0/2,4+1>();
And then Log2<0,5>:
return (0 <= 1) ? 5 : Log2<0/2,5+1>();
And so on, and so on. At some point the compiler realizes that it never stops, and gives up. But at no point does it say, "Wait, the condition of that ternary operator is false, I don't need to instantiate the right-hand side." That's because the C++ standard doesn't allow it to. The function body must be instantiated completely.
Now look at my solution. There's no template. There's just a function. The compiler sees it and goes, "Hey, here's a function. Awesome, let me put in a call to that function here." And then at some point (it might be immediately, it might be a lot later, depending on the compiler), it might (but is not forced to, in this case) say, "Hey, wait, this function is constexpr and I know the parameter values, let me evaluate that." Now it goes ahead and evaluates Log2(8, 0). Remember the body:
return (n <= 1) ? p : Log2(n / 2, p + 1);
"OK", the compiler says, "I just want to know what this function returns. Let's see, 8 <= 1 is false, so look at the right side. Log2(4, 1), huh? Let me look at that. OK, 4 <= 1 is also false, so it must be Log2(2, 2). What's that, 2 <= 1? Also false, so it's Log2(1, 3). Hey, 1 <= 1 is true, so let me take that 3 and return it. All the way up the call stack."
So it comes up with the answer 3. It doesn't go into endless recursion because it's evaluating the function with full knowledge of values and semantics, not just stupidly building up ASTs.
I hope that helps.

As others already said: The compiler won't evaluate a conditional expression such as if/else or a ternary operator ?:. However, there is still a way to make this conditional expression compile time:
#include <cstddef> // size_t is shorter than unsigned int, it's a matter of taste in this case
#include <iostream> // to show our results
#include <type_traits> // needed for the mighty std::enable_if
template<size_t N, size_t P = 0>
constexpr typename std::enable_if<(N <= 1), size_t>::type Log2()
{
return P;
}
template<size_t N, size_t P = 0>
constexpr typename std::enable_if<!(N <= 1), size_t>::type Log2()
{
return Log2<N / 2, P + 1>();
}
int main()
{
std::cout << Log2<1>() << "\n";
std::cout << Log2<2>() << "\n";
std::cout << Log2<4>() << "\n";
std::cout << Log2<8>() << "\n";
std::cout << Log2<16>() << "\n";
}
What this does is rather obvious: If N <= 1, the first branch should be evaluated, thus Log2<0, P>() and Log2<1, P>() should evaluate to P. If N <= 1, the upper method is enabled as this function header is valid. For everything else, i.e. N >= 2 or !(N <= 1), we need to recurse, which is done by the second method.

Related

Template factorial function without template specialization

I don't understand the following behavior.
The following code, aimed at computing the factorial at compile time, doesn't even compile:
#include <iostream>
using namespace std;
template<int N>
int f() {
if (N == 1) return 1; // we exit the recursion at 1 instead of 0
return N*f<N-1>();
}
int main() {
cout << f<5>() << endl;
return 0;
}
and throws the following error:
...$ g++ factorial.cpp && ./a.out
factorial.cpp: In instantiation of ‘int f() [with int N = -894]’:
factorial.cpp:7:18: recursively required from ‘int f() [with int N = 4]’
factorial.cpp:7:18: required from ‘int f() [with int N = 5]’
factorial.cpp:15:16: required from here
factorial.cpp:7:18: fatal error: template instantiation depth exceeds maximum of 900 (use ‘-ftemplate-depth=’ to increase the maximum)
7 | return N*f<N-1>();
| ~~~~~~^~
compilation terminated.
whereas, upon adding the specialization for N == 0 (which the template above doesn't even reach),
template<>
int f<0>() {
cout << "Hello, I'm the specialization.\n";
return 1;
}
the code compiles and give the correct output of, even if the specialization is never used,
...$ g++ factorial.cpp && ./a.out
120
The issue here is that your if statement is a run time construct. When you have
int f() {
if (N == 1) return 1; // we exit the recursion at 1 instead of 0
return N*f<N-1>();
}
the f<N-1> is instantiated as it may be called. Even though the if condition will stop it from calling f<0>, the compiler still has to instantiate it since it is part of the function. That means it instantiates f<4>, which instantiates f<3>, which instantiates f<2>, and on and on it will go forever.
The Pre C++17 way to stop this is to use a specialization for 0 which breaks that chain. Starting in C++17 with constexpr if, this is no longer needed. Using
int f() {
if constexpr (N == 1) return 1; // we exit the recursion at 1 instead of 0
else return N*f<N-1>();
}
guarantees that return N*f<N-1>(); won't even exist in the 1 case, so you don't keep going down the instantiation rabbit hole.
The problem is that f<N>() always instantiates f<N-1>() whether that if branch is taken or not. Unless properly terminated, that would create infinite recursion at compile time (i.e. it would attempt instantiating F<0>, then f<-1>, then f<-2> and so on). Obviously you should terminate that recursion somehow.
Apart from constexpr solution and specialization suggested by NathanOliver, you may terminate the recursion explicitly:
template <int N>
inline int f()
{
if (N <= 1)
return 1;
return N * f<(N <= 1) ? N : N - 1>();
}
Mind, this solution is rather poor (the same terminal condition must be repeated twice), I'm writing this answer merely to show that there are always more ways to solve the problem :- )

Is it possible to avoid errors in parts of a c++ template function that are not going to run in the end?

I have a template with two integers as input. One may have a larger type than the other. My code does a shift accordingly so the results fits the destination type.
Here is a basic idea of the function:
template<typename S, typename D>
D convert(S a)
{
return static_cast<D>(a);
}
When the size between S and D changes, though, I want to shift the value. So I add a couple of conditions:
if(sizeof(S) < sizeof(D))
{
return a << (sizeof(D) - sizeof(S)) * 8;
}
if(sizeof(S) > sizeof(D))
{
return a >> (sizeof(S) - sizeof(D)) * 8;
}
The problem is that I get these errors:
conversions.cpp: In instantiation of ‘void convert(buffer_&) [with S = unsigned char; D = short unsigned int; buffer_t = std::vector]’:
conversions.cpp: required from here
conversions.cpp: error: right shift count >= width of type [-Werror=shift-count-overflow]
d[idx] = convert_sign<S, D>(static_cast<std::int64_t>(s[idx]) >> (sizeof(S) - sizeof(D)) * 8);
_Note: for those not understanding, the (sizeof(S) - sizeof(D)) or (sizeof(D) - sizeof(S)) when in the wrong if() block is going to be negative and thus viewed as really large as a shift parameter (since shift parameters are taken as unsigned values, it is very large and not negative, anyway the sizeof() returns a std::size_t which is unsigned.)
Obviously, I can use a pragma to ignore the warning and be done with it.
What I was expecting, though, was that the if() that has false would just not get compiled so there would no errors since that happens at compile time (i.e. the compiler knows whether the if() block will be executed or not at the time it gets compiled.) Is there a way to not use the pragma and still avoid the error?
What I was expecting, though, was that the if() that has false would just not get compiled so there would no errors since that happens at compile time (i.e. the compiler knows whether the if() block will be executed or not at the time it gets compiled.)
You're describing the behavior of if constexpr that, unfortunately, is available only starting from C++17
When you write
if constexpr ( some_compile_time_test )
some_code_1;
else
some_code_2;
where some_compile_time_test is a test that can be decided compile-time (as sizeof(S) < sizeof(D)), the compiler compile some_code_1 -- and completely ignore some_code_2 -- when the test is true and vice versa, otherwise
If you only write
if ( some_test )
some_code_1;
else
some_code_2;
isn't important if the test some_test is deducible compile-time or not: the compiler can optimize the code ignoring the part unused but that part must be compilable.
Pre C++17 (mainly, but not only, C++11 and C++14) you have to develop two (or more) different functions/methods.
Look for "SFINAE" and "tag dispatching" to see a couple of useful methods.
An example of SFINAE
template <typename S, typename D>
typename std::enable_if<(sizeof(S)<sizeof(D)), S>::type convert (S a)
{ return a << (sizeof(D) - sizeof(S)) * 8; }
template <typename S, typename D>
typename std::enable_if<(sizeof(S)>sizeof(D)), S>::type convert (S a)
{ return a >> (sizeof(S) - sizeof(D)) * 8; }
and an example of tag dispatching (caution for both: code not tested)
template <typename S, typename D>
S convert (S a, std::true_type)
{ return a << (sizeof(D) - sizeof(S)) * 8; }
template <typename S, typename D>
S convert (S a, std::false_type)
{ return a >> (sizeof(S) - sizeof(D)) * 8; }
template <typename S, typename D>
S convert (S a)
{ return convert<S, D>(a, std::integral_constant<bool, (sizeof(S)<sizeof(D))>{}); }

Strange SFINAE code

I found this code in conjunction to SFINAE:
template<int I> void div(char(*)[I % 2 == 0] = 0) {
// this overload is selected when I is even
}
template<int I> void div(char(*)[I % 2 == 1] = 0) {
// this overload is selected when I is odd
}
How does it work? It looks like an unnamed parameter array but I don't understand how the subscripting helps in overload resolution.
Array bounds in C++ cannot be zero. If the expression (e.g., I % 2 == 0) is false, that's converted to zero, resulting in an invalid type and therefore substitution failure.
Essentially, it's an obfuscated version of std::enable_if.
Remember this is called like this: div<1234>() => first overload is called.
To understand you only need to look at the argument:
char(*)[I % 2 == 0] = 0
This means it is pointer to an array of chars. This array has the default value 0. This means you could also do char a[] = "hello world"; div<1234>(a);
I % 2 == 0 is evaluated at compile time. You should know what it does. Even integers make this true, Odd integers make this false. True evaluates to 1, false evaluates to 0. However there is no such thing as an array with zero elements. This is what you call a SFINAE error. It doesn't mean it is a fundamental error, just that the blanks in the template could not be substituted adequately. The template doesn't match.
As mentioned by T.C. since you cannot have arrays of 0 element, when the condition is false, the boolean false is converted to 0: the type becomes char (*)[0] (pointer to a char array of size 0) and this triggers SFINAE.
Now, in a more conventional (and readable) way, you would usually let std::enable_if do the job:
template <int I, std::enable_if_t<I%2>* = nullptr>
div() {
std::cout << "I (" << I <<") am odd." << std::endl;
}
template <int I, std::enable_if_t<!(I%2)>* = nullptr>
div() {
std::cout << "I (" << I <<") am even." << std::endl;
}
As demonstrated here on Coliru.

constexpr function not calculate value in compile time

I want to compare meta programming and use of constexpr in c++0x.
then I write a fib function in both model.
when I use meta programming model, answer print out very fast because it calculated in compile time. but when I use constexpr funcion it calculate value in run time, not in compile time.
I using g++( gcc ) 4.8 .can any body help me?
#include <iostream>
using namespace std;
#define NUM 42
template <unsigned int N>
struct Fibonacci {
enum { value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value };
};
template <>
struct Fibonacci<1> {
enum { value = 1 };
};
template <>
struct Fibonacci<0> {
enum { value = 1 };
};
constexpr unsigned int fib(unsigned int n)
{
return (n > 1 ? fib(n-1) + fib(n-2) : 1 );
}
int main()
{
cout << "Meta_fib(NUM) : " << Fibonacci<NUM>::value << endl; // compile time :)
cout << "Constexpr_fib(NUM) : " << fib(NUM) << endl; // run time :-?
return 0;
}
I believe the reason is that constexpr is not guaranteed to execute at compile-time. To enforce compile-time evaluation, you have to assign it to a compile-time alias. Like,
enum {i = fib(NUM)};
With gcc, at least, you can get the constexpr value to be computed at compile time by making it a static variable:
static const unsigned fibNUM = fib(NUM);
As I read the standard, it's still allowed to compute the value at startup, but in practice it will be computed at compile time.
A simple test to see if your constexpr are really being done at compile-time is to use an std::array:
#include <array>
std::array<int, Fibonacci<5>::value> arr;
std::array<int, fib(5)> arr2;
gcc has no complaints.
See this comment by Bjarne Stroustrup:
... according to the standard a constexpr function may be evaluated at
compiler time or run time unless it is used as a constant expression,
in which case it must be evaluated at compile-time. To guarantee
compile-time evaluation, we must either use it where a constant
expression is required (e.g., as an array bound or as a case label) or
use it to initialize a constexpr. I would hope that no self-respecting
compiler would miss the optimization opportunity to do what I
originally said: "A constexpr function is evaluated at compile time if
all its arguments are constant expressions."
constexpr is not guaranteed to be evaluated at compile time. This means, compiler can choose whether to evaluate at compile time or at run time.
You can try to assign it to a compile time constant and check like this...
const long i = fib(NUM);// here i should be initialized at the time of
// declaration
cout << "Meta_fib(NUM) : " << Fibonacci<NUM>::value << endl;
cout << "Constexpr_fib(NUM) : " << i << endl;

Recursive template for compile-time bit mask

I'm trying to create a compile-time bit mask using metaprograming techniques, my idea is to create something like this:
unsigned int Mask3 = Mask<2>(); // value = 0x03 = b00000000000000000000000000000011
unsigned int Mask3 = Mask<3>(); // value = 0x07 = b00000000000000000000000000000111
unsigned int Mask3 = Mask<7>(); // value = 0x7F = b00000000000000000000000001111111
The code that I'm trying is this:
template <const unsigned int N> const unsigned int Mask()
{
if (N <= 1)
{
return 1;
}
else
{
return ((1 << N) | Mask<N - 1>());
}
}
return 1;
But it result in tons pairs of warnings:
warning C4554: '<<' : check operator precedence for possible error
warning C4293: '<<' : shift count negative or too big
And in the end, the compile error:
error C1202: recursive type or function dependency context too complex.
So, I deduce that the recursivity never ends and falls into a compiler infinite loop but I'm don't understanding WHY.
As has already been pointed out, you're depending on a runtime check to
stop a compile time recursion, which can't work. More importantly,
perhaps, for what you want to do, is that you're defining a function,
which has no value until you call it. So even after you stop the
recursion with a specialization, you still have a nested sequence of
functions, which will be called at runtime.
If you want full compile time evaluation, you must define a static data
member of a class template, since that's the only way a compile time
constant can appear in a template. Something like:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N - 1)) | Mask<N - 1>::value;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(I've also corrected the numerical values you got wrong.)
Of course, you don't need anything this complicated. The following
should do the trick:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N + 1)) - 1;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(You still need the specialization for 0. Otherwise, 0 means all bits
set.)
Finally, of course: to access the value, you need to write something
like Mask<3>::value. (You might want to wrap this in a macro.)
It doesn't need to be recursive. This should work just fine :
template <const unsigned int N> const unsigned int Mask()
{
return ((1 << N) - 1);
}
It doesn't even need to be a template really. An (inlined) function is ok.
Note that if you want to support any value of N, specifically N >= sizeof(unsigned int) * CHAR_BIT, you probably want to treat those as a special case.
A template is created at compile time, but you are relying on run time behavior to stop the recursion.
For example, if you instantiate Mask<2>, it is going to use Mask<1>, which is going to use Mask<0>, which is going to use Mask<-1>, etc.
You have a runtime check for N being <= 1, but this doesn't help when it's compiling. It still creates an infinite sequence of functions.
To blunt template instantiation recursion you need to introduce one explicit specialization:
template <0> const unsigned int Mask()
{
return 1;
}
Your recursion never ends, because compiler tries to generate template implementation for both if-branches. So, when it generates Mask<0> it also generates Mask<0xffffffff> and so on
C++11 -- no recursion or templates:
constexpr unsigned mask(unsigned N) { return unsigned(~(-1<<N)); }
So far the answers only addressed the second error (C1202), but you asked more than that.
Warning C4554 is caused by a Microsoft compiler bug involving template parameters and the << operator. So, (1 << N) generates a warning. If N were an ordinary parameter, there would be no warning of course.
The very simple workaround is to use (1 << (N)) instead of (1 << N), and C4554 goes away!