Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr - function cannot be used in a constant expression

I want to compute a lookup table at compile time for a mathematical function in a given range and then retrieve values from the table at run time. My code is as follows:

#include <iostream>
#include <cmath>


template<int size>
class LookupTable {
public:
constexpr LookupTable(double xMin, double xMax) : array(), xMin(xMin), xMax(xMax), dx((xMax - xMin) / (size - 1)) {
    for(auto i = 0; i < size; ++i)
        array[i] = exp(xMin + i * dx);
}

constexpr double operator()(double x) const {
    return array[std::min(std::max(static_cast<int>((x - xMin) / dx), 0), size-1)];
}

private:
double array[size];
double xMin;
double xMax;
double dx;
};



int main() {
    const double x = 0.5;
    constexpr LookupTable<10000> table(0.0, 1.0);
    std::cout << "f(x) = " << table(x) << std::endl;  // evaluated at compile time ?
    std::cout << "f(x) = " << LookupTable<10000>(0.0, 1.0)(x) << std::endl;  // evaluated at run time ?
    return 0;
}

The code compiles and runs on gcc 5.1 and above but not on Clang 3.8. Clang's error messages are: constexpr variable 'table' must be initialized by a constant expression and non-constexpr function 'exp' cannot be used in a constant expression.

When I remove the constexpr in:

constexpr LookupTable<10000> table(0.0, 1.0);

then the code compiles and runs on Clang as well.

My questions are:

  • What is the meaning of the error message "function 'exp' cannot be used in a constant expression" ? And is there a workaround?
  • Does that mean that when I declare LookupTable<10000> table(0.0, 1.0); without the constexpr, then the table precomputations happen at run-time? I am using an online compiling tool so I do not have an option to benchmark the code right now.
  • I would like to generalize the code and templatize the mathematical function. It works fine with functors but is it possible to use lambdas?

Thanks

like image 944
greg Avatar asked Apr 08 '16 10:04

greg


1 Answers

This appears to be a non-conforming extension of gcc since exp() is declared without constexpr in <cmath>:

17.6.5.6 constexpr functions and constructors [constexpr.functions]

1 This standard explicitly requires that certain standard library functions are constexpr (7.1.5). An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.

Without the constexpr in front of your LookupTable, it will indeed be initalized at runtime. A work-around is to make it a static variable, so that you can initialize it at start-up time.

If you want constexpr math functions, you need to write your own, or alternatively, write a Standard proposal that the current <cmath> library is modified to be constexpr.

like image 98
TemplateRex Avatar answered Sep 21 '22 11:09

TemplateRex