3

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 some of the comments. 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 this is the plan of the Std, so one can rely on it.

towi
  • 21,587
  • 28
  • 106
  • 187
  • 1
    Consider how `01` and `1` mean exactly the same thing when interpreted as `int`, yet you may want `01_bin` and `1_bin` interpreted differently (a bit string of length 2 vs. a bit string of length 1). Regardless of what the standard says (that's answered already), it makes sense that you receive the exact spelling that the user used. It's up to you to decide which spelling differences matter and which don't. –  Nov 13 '16 at 16:46

2 Answers2

4

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.

Community
  • 1
  • 1
krzaq
  • 16,240
  • 4
  • 46
  • 61
0

As much as I read here the separator is allowed only when you get the literal as a number, not when the operator is a raw literal. That means you will get rid of the separator by the compiler if the operator parameter type is unsigned long long, not if it's one of the raw ones that get C-string or char.

Yehezkel B.
  • 1,140
  • 6
  • 10
  • That sort of would be amazing! 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?' – towi Nov 13 '16 at 17:17
  • 1
    Looking in [this](http://stackoverflow.com/a/40265094/4299382) answer in the linked question seems like this is consistent with the `chrono` behavior described there, where raw literal operator gets the separator as is while the cooked one (getting `ull`) ignores it. Unfortunately, I can't find clear enough reference in the standard text. – Yehezkel B. Nov 13 '16 at 17:32
  • 1
    If `` uses it, @howard-hinnant often watches this site. Maybe He'll see it. – towi Nov 13 '16 at 19:19