Reputation: 27038
Update: I posted my own answer below And there's a longer version of this matter here: http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals
Question:
I've made a simple constexpr
user defined literal _X
that gets the value as an unsigned long long (that's how numeral user defined literals work: http://en.cppreference.com/w/cpp/language/user_literal), and then I make sure that the value fits in a signed long long.
It all works well (too big values cause compilation error), but only when I explicitly create a variable such as
constexpr auto a= 150_X;
If instead I write something typical like
cout << 150_X << endl;;
the tests are not performed at compile time.
Are constexpr functions only executed at compile time if they are assigned to a constexpr variable? (I could not find that in the standard)
Is it possible to achieve the safe behaviour of _X
that I'm looking for?
Full example:
#include<iostream>
#include<stdexcept>
inline constexpr long long testConv(unsigned long long v) {
return (v > 100 ) ? throw std::exception() : v;
} // will eventually use actual limit from numeric_limits
inline constexpr long long operator "" _X(unsigned long long f) {
return testConv(f) ;
}
int main(){
constexpr auto a= 5_X;
std::cout << a << std::endl;
std::cout << 200_X << std::endl; // This bad literal is accepted at compile time
constexpr auto c=250_X; // This bad literal is not accepted at compile time
std::cout << c << std::endl;
}
oh, for reference: I used gcc4.7.2.
Upvotes: 7
Views: 3114
Reputation: 27038
Self answer: I found a complete solution, inspired by the comments and other answers to my question, and other questions such as https://stackoverflow.com/a/13384317/1149664.
The solution is to use the template form of user defined literals and sum up the number manually, multiplying the sum based on the already parsed digits by 10.
I wrote a detailed version of this self-answer here: http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals
template<char... Chars>
int operator"" _steps(){
return {litparser<0,Chars...>::value};
}
Litparser is a little template meta-program which takes a list of characters as arguments expanded from the input characters held by the Chars parameter pack.
typedef unsigned long long ULL;
// Delcare the litparser
template<ULL Sum, char... Chars> struct litparser;
// Specialize on the case where there's at least one character left:
template<ULL Sum, char Head, char... Rest>
struct litparser<Sum, Head, Rest...> {
// parse a digit. recurse with new sum and ramaining digits
static const ULL value = litparser<
(Head <'0' || Head >'9') ? throw std::exception() :
Sum*10 + Head-'0' , Rest...>::value;
};
// When 'Rest' finally is empty, we reach this terminating case
template<ULL Sum> struct litparser<Sum> {
static const ULL value = Sum;
};
Upvotes: 4
Reputation: 5127
Constexpr functions need not be executed at compile-time. But your goal can be achieved. For better understanding of the problem, and an example how to create a iteral that is always evaluated at compile-time, I recommend this post.
Upvotes: 1
Reputation: 241861
constexpr
functions may be executed at compile time; that is, they are eligible to be used in constant expressions. If they're not used in a constant expression, there's no point executing them at compile time, although I think it's allowed.
Since you're not allowed to declare a parameter as constexpr
(section 7.1.5/1) [1], I don't think there is any way to force evaluation of operator "" _X(unsigned long long)
at compile time, but you can probably do it with template<char...> operator "" _X()
If the constexpr
function is called within a constant expression, the argument will be a constant expression (and if it is not, then the call is not a constant expression). However, you cannot force the call to be a constant expression by declaring the parameter to be constexpr
, because you're not allowed to declare parameters as constexpr
, see reference to standard.
[Note 1]: Thanks to @LightnessRacesInOrbit for searching the standard to justify the claim in paragraph two.
Upvotes: 3