Reputation: 2299
I'm working on trying to get a Linux based project, written in C++17 to work on OSX (Mojave). Most everything compiles just fine, until I get to this file: ClassName.hpp
:
class ClassName {
public:
static constexpr double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1 = 2; // represents 0.99
static constexpr double DEFAULT_TARGET_TFINAL_DIGITS_FROM_0 = 10; // represents 1e-10
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
static constexpr double DEFAULT_TARGET_FINAL_PBAD = pow(10,-DEFAULT_TARGET_TFINAL_DIGITS_FROM_0);
static constexpr double DEFAULT_ERROR_TOL_DIGITS = 0.9; // as a fraction of digits in the last place from the above.
static constexpr double DEFAULT_SAMPLE_TIME = 1;
// more unrelated code
};
When compiling this I get the following error:
error: constexpr variable
'DEFAULT_TARGET_INITIAL_PBAD' must be initialized by a constant expression
...double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ClassName.hpp: note: non-constexpr function 'pow<int, double>'
cannot be used in a constant expression
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITI...
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/math.h:968:1: note:
declared here
pow(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
So for some reason this works on Ubuntu and CentOS. I think it has to do with how pow
is defined? But I'm not sure how to fix it, or if that is even the issue. I've also tried removing constexpr
from DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1
and DEFAULT_TARGET_TFINAL_DIGITS_FROM_0
and making them const
but still run into the same issue.
Upvotes: 2
Views: 2784
Reputation: 4289
First, you can't initialize constexpr
class members with functions that aren't constexpr
and std::pow
isn't constepxr
in standard C++17 . The workaround is to declare them const
. While they can't be used in places that require a compile time const
they are immutable. A traditional approach is declaring them in header which you include as needed in source files. Then you hneed one implementation file that defines the static const members.
If your code requires compile time const's or constexpr your only option is to write your own pow
.
Here's one way to initialize const statics with functions that are not constexpr
prior to executing the main() using a portion of your question that shows the technique:
Create a header, constinit.h, that declares the class
// include header guards
// declare the static consts
struct ClassName {
static double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1; // represents 0.99
static double DEFAULT_TARGET_INITIAL_PBAD; // to be initialized by pow
};
Create an implementation file that initializes the statics:
#include "constinit.h"
#include <cmath>
double ClassName::DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1{ 2 }; // represents 0.99
double ClassName::DEFAULT_TARGET_INITIAL_PBAD = (1 - std::pow(10, -DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
To use the statics:
#include <iostream>
#include "constinit.h"
int main()
{
std::cout << ClassName::DEFAULT_TARGET_INITIAL_PBAD << std::endl;
}
If constexpr
for compile time initialization is required you need to define your own constexpr
pow function. This works in C++17:
#pragma once // or header guards per your preference
constexpr double my_pow(double x, int exp)
{
int sign = 1;
if (exp < 0)
{
sign = -1;
exp = -exp;
}
if (exp == 0)
return x < 0 ? -1.0 : 1.0;
double ret = x;
while (--exp)
ret *= x;
return sign > 0 ? ret : 1.0/ret;
}
class ClassName {
public:
static constexpr double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1 = 2; // represents 0.99
static constexpr double DEFAULT_TARGET_TFINAL_DIGITS_FROM_0 = 10; // represents 1e-10
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1 - my_pow(10, -DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
static constexpr double DEFAULT_TARGET_FINAL_PBAD = my_pow(10, -DEFAULT_TARGET_TFINAL_DIGITS_FROM_0);
static constexpr double DEFAULT_ERROR_TOL_DIGITS = 0.9; // as a fraction of digits in the last place from the above.
static constexpr double DEFAULT_SAMPLE_TIME = 1;
// more unrelated code
};
Upvotes: 4