Integer sequence of chars from user-defined literal taking strings as parameters
Asked Answered
E

1

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'>?

Exchequer answered 30/1, 2016 at 4:41 Comment(15)
N3599 may make it into C++1Z.Independence
Do you really need an integer_sequence? This smells like an XY-problem.Independence
@Independence Where did you get that information? Last I heard it was rejected in EWG in favor of a string_literal<N>.Miniskirt
@Miniskirt Straight from the author.Independence
@Independence Hmm, when was this?Miniskirt
There's a GNU extension for template<typename CharT, CharT... Chars> stuff operator "" _x(); UDLs supported by gcc and clang in the meantime.Kronfeld
@Miniskirt cplusplus.github.io/EWG/ewg-active.html#66 The machinery will be accepted by LEWG, and a revision of the paper (hopefully) accepted.Independence
@Independence IIRC it was reported that EWG chose N4121 (string_literal<N>, 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.Miniskirt
@Miniskirt 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.Independence
@Independence 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...Miniskirt
@Miniskirt 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.Independence
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<sizeof(literal), literal>;. Let me know if you're interested in details.Dispersion
I am actually interested in details.Exchequer
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'};Loren
@Exchequer Well, string literals can't be non-type template arguments, but namespace-scope constants can be. This is demonstrated in [temp.arg.nontype]/3.Independence
I
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.

Independence answered 22/3, 2016 at 1:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.