7

Currently, only doubles can produce a template of chars in a user defined literal:

template <char...> double operator "" _x();
// Later
1.3_x; // OK
"1.3"_y; // C++14 does not allow a _y user-
         // defined operator to parse that as a template of chars

Is there a clever way to produce a std::integer_sequence of chars using a user defined literal. In other words, what the code of _y(const char*, std::size_t) would be so that I end up with a std::integer_sequence<char, '1', '.', '3'>?

Vincent
  • 57,703
  • 61
  • 205
  • 388
  • [N3599](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html) may make it into C++1Z. – Columbo Jan 30 '16 at 09:26
  • 1
    Do you really need an `integer_sequence`? This smells like an XY-problem. – Columbo Jan 30 '16 at 09:37
  • @Columbo Where did you get that information? Last I heard it was rejected in EWG in favor of a `string_literal`. – T.C. Jan 30 '16 at 11:36
  • @T.C. Straight [from the author](https://github.com/Arcoth/Constainer/blob/master/StaticPrintf.hxx#L929). – Columbo Jan 30 '16 at 11:41
  • @Columbo Hmm, when was this? – T.C. Jan 30 '16 at 11:46
  • There's a GNU extension for `template stuff operator "" _x();` UDLs supported by gcc and clang in the meantime. – melak47 Jan 30 '16 at 12:22
  • @T.C. https://cplusplus.github.io/EWG/ewg-active.html#66 The machinery will be accepted by LEWG, and a revision of the paper (hopefully) accepted. – Columbo Jan 30 '16 at 13:57
  • @Columbo IIRC it was reported that EWG chose N4121 (string_literal, see EWG 139) over N4236 (which is an extension of N3599 and uses a parameter pack). Not clear whether we'd get the core language support with a pack if they don't want to provide library facilities. – T.C. Jan 30 '16 at 17:08
  • @T.C. That's correct; i.e. one of them was chosen, which (if I remember Smith's mail correctly, which I can't check atm) is all EWG required (does that make sense?). Either way, there is (still) motivation, no disincentives, implementations that support it and barely any wording change necessary, I'm positive that a revised paper will be accepted. – Columbo Jan 30 '16 at 17:23
  • @Columbo we'll see, I guess. I'm not sure they'd add a facility that produces parameter packs after rejecting something that actually uses said packs. Of course, I might be pleasantly surprised... – T.C. Jan 30 '16 at 17:45
  • @T.C. They rejected the pack solution because the other one is better. That doesn't imply that string literal operator templates are useless, or that they wouldn't favor them. The code I linked requires it, and it's useful (I hope :D). Yeah, we'll see. – Columbo Jan 30 '16 at 17:53
  • 1
    If you don't want to use compiler extensions, the closest thing I know of is used like this: `constexpr const char literal[] = "delta"; using X = make_char_sequence;`. Let me know if you're interested in details. – Rumburak Feb 01 '16 at 06:16
  • I am actually interested in details. – Vincent Feb 01 '16 at 06:20
  • You should be able to expand the char pack into an array initializer: const char literal[]{Chars...}; You could even adda null at the end: char literal[]{Chars..., '\0'}; – emsr Feb 03 '16 at 03:49
  • @Vincent Well, string literals can't be non-type template arguments, but namespace-scope constants can be. This is demonstrated in [\[temp.arg.nontype\]/3](http://eel.is/c++draft/temp.arg.nontype#3). – Columbo Mar 22 '16 at 10:32

1 Answers1

0

At this point in time, the best we can (portably) do is a macro trick as demonstrated for vtmpl::string. Basically, we create a list of accesses such as

"abcd" -> {(0 < sizeof "abcd"? "abcd"[0] : 0), (1 < sizeof "abcd"? "abcd"[1] : 0), ...}

…which we trim to obtain the desired result.

The first step is easily done via BOOST_PP_ENUM, although recursive macros are also fine (definition from here):

#define VTMPL_SPLIT_1(s, x, m) m(s, x)
#define VTMPL_SPLIT_4(s, x, m)    VTMPL_SPLIT_1  (s, x, m), VTMPL_SPLIT_1  (s, x+1  , m), VTMPL_SPLIT_1  (s, x+2  , m), VTMPL_SPLIT_1  (s, x+3  , m)
#define VTMPL_SPLIT_16(s, x, m)   VTMPL_SPLIT_4  (s, x, m), VTMPL_SPLIT_4  (s, x+4  , m), VTMPL_SPLIT_4  (s, x+8  , m), VTMPL_SPLIT_4  (s, x+12 , m)
#define VTMPL_SPLIT_64(s, x, m)   VTMPL_SPLIT_16 (s, x, m), VTMPL_SPLIT_16 (s, x+16 , m), VTMPL_SPLIT_16 (s, x+32 , m), VTMPL_SPLIT_16 (s, x+48 , m)
#define VTMPL_SPLIT_256(s, x, m)  VTMPL_SPLIT_64 (s, x, m), VTMPL_SPLIT_64 (s, x+64 , m), VTMPL_SPLIT_64 (s, x+128, m), VTMPL_SPLIT_64 (s, x+194, m)
#define VTMPL_SPLIT_1024(s, x, m) VTMPL_SPLIT_256(s, x, m), VTMPL_SPLIT_256(s, x+256, m), VTMPL_SPLIT_256(s, x+512, m), VTMPL_SPLIT_256(s, x+768, m)

Usage of the above looks like this (trimming included):

#define VTMPL_STRING_IMPL(str, n) vtmpl::rtrim<vtmpl::value_list<decltype(*str), VTMPL_SPLIT_##n(str, 0, VTMPL_ARRAY_SPLIT)>>::type
#
#define VTMPL_STRING(str) VTMPL_STRING_IMPL(str, 64  )

Where rtrim is defined in algorithms.hxx.

Columbo
  • 60,038
  • 8
  • 155
  • 203