c++g++c++14constexprcmath

function exp(exponential) cannot be used in a constant expression - gcc extension


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:

Thanks


Solution

  • 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.