4

I was taking a look at the cppreference page for user defined literals, and I think I understand everything except a few examples

template <char...> double operator "" _π(); // OK 

How does this operator work? How can you call it?

double operator"" _Z(long double); // error: all names that begin with underscore // followed by uppercase letter are reserved double operator""_Z(long double); // OK: even though _Z is reserved ""_Z is allowed 

What is the difference between the above two functions? What would be the difference in calling the first function as opposed to the second if the first were not an error?

Thanks!

2 Answers 2

8
template <char...> double operator "" _π(); // OK 

How does this operator work? How can you call it?

1.234_π will call operator "" _π<'1', '.', '2', '3', '4'>(). This form allows you to detect differences in spelling that would ordinarily be undetectable (1.2 vs 1.20, for example), and allows you to avoid rounding issues due to 1.2 not being exactly representable in even long double.

double operator"" _Z(long double); // error: all names that begin with underscore // followed by uppercase letter are reserved double operator""_Z(long double); // OK: even though _Z is reserved ""_Z is allowed 

What is the difference between the above two functions?

The C++ standard defines the grammar in terms of tokens, which you can sort of interpret as words. "" _Z is two tokens, "" and _Z. ""_Z is a single token.

This distinction matters: given #define S " world!", and then "Hello" S, the whitespace is what makes S a standalone token, preventing it from being seen as a user-defined literal suffix.

For easier coding, both "" _Z and ""_Z syntaxes are generally allowed when defining these functions, but the "" _Z syntax requires _Z to be seen as an identifier. This can cause problems when an implementation predefines _Z as a macro, or declares it as a custom keyword.

Sign up to request clarification or add additional context in comments.

6 Comments

Do you know why with the literal, something like this "something"_π does not call operator "" _π<'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g'>()? How can i change the declaration of that user defined literal to make those characters be passed as template arguments?
@Curious That's not possible, passing the individual characters as template arguments is only possible with numeric literals.
any idea why thats so? I don't understand why characters would not be supported as well..
@Curious I'm guessing simply because with numeric literals, concrete examples were found where the template form helped, and with string and character literals, not so.
It just seems like you have to go out of your way and not support regular string literals.. Is there any other way to achieve this?
|
1

As far as I understand there is not difference between the two signitures.

The issue is that the identifier _Z is technically reserved by the standard. The main difference is that there is a space:

double operator""/*space*/_Z(long double); double operator""_Z(long double); 

Removing the space is basically a workaround that in theory would suppress the error (or more likely a warning).

As far as how you use them, did you look at the examples from the link you listed?

#include <iostream> // used as conversion constexpr long double operator"" _deg ( long double deg ) { return deg*3.141592/180; } // used with custom type struct mytype { mytype ( unsigned long long m):m(m){} unsigned long long m; }; mytype operator"" _mytype ( unsigned long long n ) { return mytype(n); } // used for side-effects void operator"" _print ( const char* str ) { std::cout << str; } int main(){ double x = 90.0_deg; std::cout << std::fixed << x << '\n'; mytype y = 123_mytype; std::cout << y.m << '\n'; 0x123ABC_print; } 

The idea behind the user defined literals is to allow the creation of an operator that can be applied to built in types that can convert the built in literal to another type.

EDIT:

To call one of these operators you just need to append the operator as a suffix to a value literal. So given:

// used as conversion constexpr long double operator"" _deg ( long double deg ) { return deg*3.141592/180; } 

The calling code could be for example:

long double d = 45_deg; 

As far as using template <char...> double operator "" _π(); Maybe take a look at this.

7 Comments

I did look at the examples in the link but I did not understand what the difference was in the two _Z operators, if the _Z was not reserved then how would you call it? Would that also be a user defined literal? What does the extra space mean? Also the part was left unanswered.
Sorry, I do not think i am being clear in my question. What I meant to ask about the difference between the two _Z things was what exactly the space meant? I know how to call the operator in the usual case, but what does the space mean? Is it always an error?
@Curious - If you read the cppreference close enough it explains that ""_Z (without a space) is ok, even though _Z is reserved. It also shows that the even more controversial complex<float> literal ""if (again no space) must work, even though if is a keyword.
"Basically: operator""_Z && operator"" _Z are two different identifiers and the latter is reserved." -- Huh? No, this is totally wrong. operator""_Z and operator"" _Z, if valid, would be the exact same function. Try it yourself with that operator"" _deg: add an operator""_deg and see if you get a redefinition error. The problem with operator"" _Z is that because _Z is reserved for implementation use, the implementation could e.g. define it as a macro expanding to anything you like. operator""_Z avoids that problem because _Z is not a separate token there, it's part of the ""_Z token.
_π(char...c) and double d = 'c'_π; -- Sorry, but this is clearly just guessing, and you've guessed badly.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.