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).
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
精彩评论