1

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
geometrian
  • 14,775
  • 10
  • 56
  • 132
  • either `4L` or `static_cast(4)` – Richard Critten Aug 27 '18 at 21:34
  • `using long_double = long double;` and changing the `fn_ld` signature to use the typedef will fix the issue. – cplusplusrat Aug 27 '18 at 21:36
  • Note, that `double(4)` is an explicit type conversion, just as `static_cast(4)`, so they are equivalent semantically. So the "I'm constructing an object, not casting an int" is not 100% right. – geza Aug 27 '18 at 22:00
  • @RichardCritten `4L` is long int, you're thinking of `4.L` – M.M Aug 27 '18 at 23:41
  • The solution in my case was just to use the `L` suffix. The actual problem turns out to be more-general, so I'm voting to close my own question as a duplicate. – geometrian Aug 28 '18 at 07:02

2 Answers2

1

The C++ grammar does not allow you to have a space in the type name when you do type(value).

Instead you can use the appropriate suffix instead of trying to use type(value). For a long double you can use l/L like

return pow( 4.0L, 3.0L );
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I forgot to ask for it in my question, but I'm glad you added the clarifications about what's going on behind the scenes with explicit type conversion (but even besides this, this is best answer).¶ For an object type, my syntax would semantically call a constructor; it had been my impression primitive types did this too. – geometrian Aug 28 '18 at 07:00
  • @imallett primitive types don't have constructors. For class types all of the syntaxes call a constructor – M.M Aug 28 '18 at 11:44
  • The point is, my previous mental model could be reproduced by assuming that primitive types have implicit, compiler-generated constructors. – geometrian Aug 28 '18 at 15:25