Check compile-time conversion (constexpr and user literals)

Update: I posted my own answer below. And here is a longer version of this question: http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals

Question:

I made a simple constexpr user literal _X , which gets the value as unsigned long long (how the user-defined numeric literals work: http://en.cppreference.com/w/cpp/language/user_literal ), and then I make sure that the value corresponds to a long long sign.

Everything works well (values ​​that are too large cause a compilation error), but only when I explicitly create a variable of type

 constexpr auto a= 150_X; 

If instead I write something typical, for example

 cout << 150_X << endl;; 

tests are not executed at compile time.

  • Are there constexpr functions executed only at compile time if they are assigned to the constexpr variable? (I could not find it in the standard)

  • Is it possible to achieve the safe _X behavior 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.

+7
c ++ c ++ 11 constexpr
source share
3 answers

Autoresponse: I found a complete solution based on comments and other answers to my question, and to other questions, such as https://stackoverflow.com/a/312947/ .

The solution is to use the template form of user-defined literals and add the number manually, multiplying the amount based on the numbers already analyzed by 10.

I wrote a detailed version of this answering machine 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 small metaprogram that takes a list of characters as arguments extended from input characters stored in the Chars parameter package.

 typedef unsigned long long ULL; // Delcare the litparser template<ULL Sum, char... Chars> struct litparser; // Specialize on the case where there 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; }; 
+4
source share

constexpr functions can be executed at compile time; that is, they can be used in constant expressions. If they are not used in constant expression, there is no point in compiling them at compile time, although I think this is allowed.

Since you are not allowed to declare the parameter as constexpr (section 7.1.5 / 1) [1], I don’t think there is a way to force the operator "" _X(unsigned long long) to be evaluated at compile time, but you can do it with template<char...> operator "" _X()

If the constexpr function constexpr called inside a constant expression, the argument will be a constant expression (and if not, then the call is not a constant expression). However, you cannot force a call to be a constant expression by declaring a constexpr parameter, because you are not allowed to declare parameters as constexpr , see Reference to the standard.


[Note 1]: Thanks to @LightnessRacesInOrbit for finding the standard to justify the application in paragraph 2.

+3
source share

Constexpr functions should not be executed at compile time. But your goal can be achieved. For a better understanding of the problem and an example of how to create an iteration that is always evaluated at compile time, I recommend this post .

+1
source share

All Articles