Search code examples
c++syntaxcastingrvaluelong-double

Constructing `long double` rvalue


Let's say I have the following C++ code:

#include <cmath>
long double fn_d() {
    return pow( double(4), double(3) );
}
long double fn_ld() {
    return powl( long double(4), long double(3) );
}

MSVC is happy with this, but both GCC and Clang get confused on the second function, writing (GCC's output):

<source>:6:34: error: expected primary-expression before 'long'
6 |     return powl( long double(4), long double(3) );
  |                                  ^~~~

Notice that fn_d(...) above, works just fine. Assuming this isn't a bug in both compilers, what am I supposed to do about it?


Note: (long double)(4) (i.e., a cast) is not okay. It trips -Wold-style-cast (which you should be using). Maybe static_cast<long double>(4)? This feels dirty: I'm constructing an object, not casting an int, even if the compiler will elide it.


Solution

  • Firstly, the original code is incorrect and it's a MSVC bug to silently accept it, see this question for standard references.


    Since powl is a non-overloaded function of signature:

    long double powl(long double x, long double y);
    

    you can just write powl(4, 3), there is implicit coversion from integer to long double.

    In the more general case your options include (long double)4, static_cast<long double>(4), 4.L, and 4.0L. The L suffix combined with the presence of . in the literal means a long double literal.


    This feels dirty: I'm constructing an object, not casting an int, even if the compiler will elide it.

    Maybe you have a misunderstanding in this area. The code double(4) is a cast; its official name is explicit type conversion (functional notation). Casts are prvalues, except for some cases that are not relevant here.

    There is literally (ha ha) no difference whatsoever in semantics between the different syntaxes that result in prvalue of type double and value 4.

    This is also true for class types; (std::string)x, std::string(x), and static_cast<std::string>(x) are all identical in semantics.