Question

After answering using boost math constants in constexpr and suggesting OP use boost's templated function for a constexpr variable instead of the non-templated constant to quell a clang error, I decided to try to see what conditions would reproduce the error in clang. Let's try to copy what boost's macro expands to:

namespace double_constants{ static const double name = 25; }

static constexpr double SEC3 = double_constants::name;

This gives the following errors (follow along on Coliru)

clang++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:5:25: error: constexpr variable 'SEC3' must be initialized by a constant expression
static constexpr double SEC3 = double_constants::name;
                        ^      ~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:32: note: read of non-constexpr variable 'name' is not allowed in a constant expression
static constexpr double SEC3 = double_constants::name;
                               ^
main.cpp:3:49: note: declared here
namespace double_constants{ static const double name = 25; }

That's fine, we expected that. Now change double to int:

namespace double_constants{ static const int name = 25; }
static constexpr double SEC3 = double_constants::name;

No error? Needless to say I am confused. I assumed the error was because the variable is defined as const instead of constexpr, unless I'm missing something. Let's take a look at cppreference:

A constexpr variable must satisfy the following requirements:

  • it must be immediately constructed or assigned a value.
  • the constructor parameters or the value to be assigned must contain only literal values, constexpr variables and functions.

If we were to interpret this literally, then clang is justified in giving an error because name is only const, not constexpr. And apparently double is a LiteralType because:

std::cout << std::is_literal_type<double>::value;

outputs 1. So why does clang cease to complain if name is int and not a double?

P.S.: Cannot reproduce on gcc.


For clarification, the static keyword is orthogonal to the issue. So is the namespace. From what I understand, the boost macro does not wrap the static const variable in a class, but in a namespace. I've narrowed it down to these four cases:

// Does not compile
const double name = 25;
constexpr int SEC3 = name;

const double name = 25;
constexpr double SEC3 = name;

// Compiles
const int name = 25;
constexpr double SEC3 = name;

const int name = 25;
constexpr int SEC3 = name;

I can't possibly be bothered to apply static in every permutation possible to see if it makes a difference, but I doubt it does.

Was it helpful?

Solution

It's not a bug. Unfortunately the C++ standard has different static/non-static const rules for floating point types and integer types. Please see:

Why aren't static const floats allowed?

Try constexpr instead of const as in:

namespace double_constants{ constexpr double name = 25; }

and:

constexpr double name = 25;
constexpr int SEC3 = name;

Then it should work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top