1

I am trying to defined a constexpr in terms of kilometers instead of meters using boost units. Everything I have read indicates that both lines below should work, but only the top line compiles for me in clang 10.

Here's a godbolt link for the lazy: https://godbolt.org/z/38je3z

#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/unit.hpp>
class earthConstants{
    public:
    // Works
    static constexpr boost::units::quantity<boost::units::si::length> earth_radius = (6371008.7714* boost::units::si::meters);
    // doesn't work because of boost::units::si::kilo
    static constexpr boost::units::quantity<boost::units::si::length> earth_radius_2 = (6371.0087714 * boost::units::si::kilo * boost::units::si::meters);
 }

Note: I'm an embedded firmware guy trying to learn modern c++ so if you could use short simple sentences with small words in your answer, my pea sized brain would appreciate it.

Sam
  • 289
  • 1
  • 10

1 Answers1

1

This is a workaround:

static constexpr boost::units::quantity<boost::units::si::length> earth_radius_2{6371.0087714 * boost::units::si::kilo * boost::units::si::meters};

Why is this different than the code in the question?

According to the c++17 standard, initialization with a = or direct initialization (as the solution above) are the same, if the expression on the right of = is the same type as the variable. See the discussion here. Apparently this is not the case here, and the conversion from the type on the right of = to the type on the left is presumably marked as explicit.

Here is an example.

struct X{
    explicit X(int){}
    explicit X(const X&) {}
};

int main()
{
    X a{3};
    X b = 3; // Error
}

This code does not compile because the conversion constructor from int to X is explicit; as a consequence the copy initialization X b = 3 is not accepted. If you remove the explicit keyword, then the code compiles.

francesco
  • 7,189
  • 7
  • 22
  • 49
  • I don't understand your fancy "explicit" and "Mandatory elision" words, but your fix works. Is this a bug in boost? Should I be submitting a bug report? – Sam Feb 28 '21 at 17:29
  • I think it is not a bug,but rather a consequence of the library code. For ```explicit```, you can refer to the c++ reference on [converting constructors](https://en.cppreference.com/w/cpp/language/converting_constructor). Mandatory elision means that, in some cases,the compiler is required to omit copying a temporary variable into a "normal" one. For example, if you write ```X a = X{3}```,in principle you 1) create a temporary object ```X{3}``` 2) initialize ```a```as copy of this temp 3) dispose the temp. Copy elision means that 2) and 3) are omitted and ```a``` is initialized with ```{3}```. – francesco Feb 28 '21 at 21:22