towi towi - 19 days ago 4
C++ Question

How do user-defined literals play together with digit separator?

I was just modifying an old example of my code by adding a digit separator to a user-defined literal, parsed by a variadic template:

namespace lits {
// helper for 1 arg
template<char C> int bin(); // common
template<> int bin<'1'>() { return 1; } // spec.
template<> int bin<'0'>() { return 0; } // spec.
// helper 2 or more args
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>() ;
}
// operator"" _bin
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int number = 1000'0000_bin; // <<< I added a ' here
}


Boy, was I surprised when by g++6.2.0 tried to instantiate
bin<'\''>
. It tried to pass the
'
as a
char
to my template
template<char...CS> int operator"" _bin()
! I tried it with clang++-3.9 and msvc++-19.00, same complaint, which really makes me sceptical.

I have the feeling that that may not the right behavior. I would have understood it if my literal was in quotes, say
"1000'0000"_bin
, but this form does not exist for template operator"", right?

Am I to expect the digit separator
'
in my template user-literal operators, too, now?

Update 1: in case the
'
is ok:

One could use the digit-sep as a sep for all sort of things, say, complex numbers. Would the behavior of `52.84'67.12_i' for 52.84+67.12i be well defined?'

Udpdate 2: As reaction tome of the comments

Still lack of evidence but a lock of circumstances. The following compiles:

#include <iostream>
#include <string>
using std::string;

namespace lits {
// helper
template<char C> string sx() { return string{}+C; }
// helper 2 or more args
template<char C, char D, char... ES>
string sx() {
return sx<C>() + sx<D,ES...>();
}
// operator"" _sx
template<char...CS> string operator"" _sx()
{ return sx<CS...>(); };
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n';
std::cout << 10'000'000_sx << '\n';
std::cout << 0x00af_sx << '\n';
std::cout << 0x0'c'0'a'f_sx << '\n';
std::cout << 007_sx << '\n';
std::cout << 0b01_sx << '\n';
// the following do not work:
//std::cout << 0b0a8sh3s1_sx << '\n';
//std::cout << "abcde"_sx << '\n';
}


And the output is:

10000000
10'000'000
0x00af
0x0'c'0'a'f
007
0b01


Which means that the template gets all the characters: prefixes and digit separators -- all of them. (g++-6.2.0)

As @krzaq's answer suggests, it seems so.

Answer

As far as I can tell, yes. As explained here, digit separators are legal members of user defined integer literals.

And the template integer literal is defined as:

N4140 § 2.13.8 [lex.ext] / 3

Otherwise (S contains a literal operator template), L is treated as a call of the form

operator "" X <’c1’, ’c2’, ... ’ck’>()

where n is the source character sequence c1c2...ck. [ Note: The sequence c1c2...ck can only contain characters from the basic source character set. —end note ]

There's not a word about removing separators.

Comments