开发者

Are user-defined-literals resolved at compile-time or runtime?

I wonder, because predefined literals like ULL, f, etc. are obviously resolved at compile time. The standard (2.14.8 [lex.ext]) doesn't seem to define this, but it seems to tend towards runtime:

[2.14.8 / 2]

A user-defined-literal is treated as a call to a literal operator or literal operator template (13.5.8). To determin开发者_StackOverflowe the form of this call for a given user-defined-literal L with ud-suffix X, the literal-operator-id whose literal suffix identifier is X is looked up in the context of L using the rules for unqualified name lookup (3.4.1). Let S be the set of declarations found by this lookup. S shall not be empty.

(emphasis mine.)

However, to me this seems to introduce unnecessary runtime-overhead, as literals can only be appended to values that are available at compile-time anyways like 13.37f or "hello"_x (where _x is a user-defined-literal).

Then, we got the templated user-defined-literal, that never really gets defined in the standard AFAICS (i.e., no example is given, please prove me wrong). Is that function somehow magically invoked at compile time or is it still runtime?


Yes, you get a function call. But function calls can be compile time constant expressions because of constexpr literal operator functions.

For an example, see this one. As another example to show the advanced form of constexpr computations allowed by the FDIS, to have compile time base-26 literals you can do

typedef unsigned long long ull;

constexpr ull base26(char const *s, ull ps) {
  return (*s && !(*s >= 'a' && *s <= 'z')) ? throw "bad char!" :
    (!*s ? ps : base26(s + 1, (ps * 26ULL) + (*s - 'a')));
}

constexpr ull operator "" _26(char const *s, std::size_t len) {
  return base26(s, 0);
}

Saying "bcd-"_26 will evaluate a throw-expression, and thereby cause the return value to become non-constant. In turn, it causes any use of "bcd-"_26 as a constant expression to become ill-formed, and any non-constant use to throw at runtime. The allowed form "bcd"_26 evaluates to a constant expression of the respective computed value.

Note that reading from string literals is not explicitly allowed by the FDIS, however it presents no problem and GCC supports this (the character lvalue reference is a constant expression and the character's value is known at compile time). IMO if one squints, one can read the FDIS as if this is allowed to do.

Then, we got the templated user-defined-literal, that never really gets defined in the standard AFAICS (i.e., no example is given, please prove me wrong)

The treatment of literals as invoking literal operator templates is defined in 2.14.8. You find more examples at 13.5.8 that detail on the literal operator function/function templates itself.

Is that function somehow magically invoked at compile time or is it still runtime?

The keyword is function invocation substitution. See 7.1.5.


@Johannes S is correct of course, but I'd like to add clearly (since I faced this), that even for constexpr user defined literals, the parameters are not considered constexpr or compile time constant, for example in the sense that they can not be used as integer constants for templates.

In addition, only things like this will actually give compile-time evaluation:

inline constexpr long long _xx(unsigned long long v) {
  return (v > 100 ) ? throw std::exception() : v; 
}
constexpr auto a= 150_xx;

So, that will not compile. But this will:

cout << 150_xx << endl;

And the following is not allowed:

inline constexpr long long _xx(unsigned long long v) {
  return some_trait<v>::value; 
}

That's annoying, but natural considering that (other) constexpr functions can be called also during execution.

Only for integer user-defined literals is it possible to force compile-time processing, by using the template form. Examples in my question and self answer: https://stackoverflow.com/a/13869688/1149664

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜