为什么我必须对用户定义的文字使用 long double?

Why do I have to use long double for user defined literals?

以下用户定义文字遗漏了一个错误:

constexpr double operator "" _kg(double q)
{
   return q*1000;
}

但如果添加 long,错误将消失,代码将按如下方式工作:

constexpr double operator "" _kg(long double q)
{
   return q*1000;
}

错误是:

‘constexpr double operator""_kg(double)’ has invalid argument list

问题仅由参数引起,return类型可以是double而不是long

为什么需要 long

Stroustrup 有一个关于字符串文字的重要部分,他在其中陈述(来自规范):

  • 浮点字面量:由采用单个 long double 或 const char* 参数的字面量运算符接受。

http://www.stroustrup.com/C++11FAQ.html#UD-literals

C++11 草案 n3290 对用户定义文字可以采用的参数有这样的说法 (§13.5.8):

The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the following:

const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t

如您所见,double 不在该列表中,只有 long double 在。因此,您必须将其用于需要浮点数作为参数的用户定义文字。

Only the following parameter lists are allowed on literal operators :

  • ( const char * ) (1)
  • ( unsigned long long int ) (2)
  • ( long double ) (3)
  • ( char ) (4)
  • ( wchar_t ) (5)
  • ( char16_t ) (6)
  • ( char32_t ) (7)
  • ( const char * , std::size_t ) (8)
  • ( const wchar_t * , std::size_t ) (9)
  • ( const char16_t * , std::size_t ) (10) ( const char32_t * , std::size_t ) (11)

    1. Literal operators with this parameter list are the raw literal operators, used as fallbacks for integer and floating-point user-defined literals (see above)

    2. Literal operators with these parameter lists are the first-choice literal operator for user-defined integer literals

    3. Literal operators with these parameter lists are the first-choice literal operator for user-defined floating-point literals

4-7. Literal operators with these parameter lists are called by

user-defined character literals

8-11. Literal operators with these parameter lists are called by user-defined string literals

Default arguments are not allowed C language linkage is not allowed Other than the restrictions above, literal operators and literal operator templates are normal functions (and function templates), they can be declared inline or constexpr, they may have internal or external linkage, they can be called explicitly, their addresses can be taken, etc.

来自 cpp 参考: http://en.cppreference.com/w/cpp/language/user_literal

尽管 ANSI C 未能定义一种形式的可变参数声明,该声明可以干净地处理格式不同于 double 的扩展精度 long double 类型,这导致该类型被在许多平台上实际上已被弃用(不幸的是,恕我直言,因为它是一种很好的类型,不仅适用于具有 x87 协处理器 的系统,而且适用于没有 FPU 的系统),唯一明智的方法具有适当扩展精度类型的系统来处理如下语句:

long double a = 0.1;

就是让0.1的数字字面量start life作为一个long double等于14,757,395,258,967,641,293/147,573,952,589,676,412,928;将该语句设置 a 为 7,205,759,403,792,794/72,057,594,037,927,936(大约 0.10000000000000000555,(double)0.1 的值)是荒谬的。

可以说在某些情况下,在向下转换之前将数字文字作为 long double 开始使用可能会导致它产生的值与它作为开始使用时产生的值不同doublefloat(例如,最接近 9007199791611905.0float 是 9007200328482816,高于请求值 536870911,但 (float)(double)9007199791611905.0 产生 9007199254740992,低于请求值 536870913当然,如果你想要浮点值9007200328482816.0f,你可能应该使用更接近你真正想要的十进制表示。