namespace-qualified used defined literals?

369 views
Skip to first unread message

Roland Bock

unread,
Jun 16, 2015, 1:38:10 AM6/16/15
to std-pr...@isocpp.org
Hi,

Is there any way to use a user defined literal without importing it into
the current namespace? If not, is there a proposal to do so?

I tried the following unsuccessfully with g++-5.0 -std=c++1z


#include <string>

auto hello = "hello"s; //of course not
auto world = "world"std::literals::string_literals::operator""s;
auto any = "any"(std::literals::string_literals::operator""s);
auto ideas = std::literals::string_literals::operator""s("ideas?");

int main() {}


Best,

Roland

T. C.

unread,
Jun 16, 2015, 2:29:39 AM6/16/15
to std-pr...@isocpp.org
Doesn't explicitly qualifying the name defeat the whole point of user-defined literals in the first place?

Anyway, operator""s() is a function that takes two arguments; the second argument is the length of the string (not counting the terminating null), so:

auto ideas = std::literals::string_literals::operator""s("ideas?", sizeof("ideas?") - 1); 

Since literals and string_literals are inline namespaces, this can be simplified to 

auto ideas = std::operator""s("ideas?", sizeof("ideas?") - 1); 

But, again, what's the point?

Roland Bock

unread,
Jun 16, 2015, 4:12:36 AM6/16/15
to std-pr...@isocpp.org
Boost::Hana provides a user-defined literal that I would like to use to define a compile time string in a header.

See http://ldionne.com/hana/structboost_1_1hana_1_1String.html#ad77f7afff008c2ce15739ad16a8bf0a8

I would really like to say

struct A
{
   using name_t = decltype("sample"_s);
};

But _s is not in my namespace, so I would like to qualify it (using namespace is not an option here).
And I would prefer not to provide the sizeof, which would require me to write "sample" twice.
--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

T. C.

unread,
Jun 16, 2015, 10:21:09 AM6/16/15
to std-pr...@isocpp.org
Hana's operator""_s is actually a template (which depends on a compiler extension).

So it'd actually be operator""_s<char, 's', 'a', 'm', 'p', 'l', 'e'>().

That's arguably even worse.

Roland Bock

unread,
Jun 16, 2015, 4:18:27 PM6/16/15
to std-pr...@isocpp.org
On 2015-06-16 16:21, T. C. wrote:
Hana's operator""_s is actually a template (which depends on a compiler extension).

So it'd actually be operator""_s<char, 's', 'a', 'm', 'p', 'l', 'e'>().

That's arguably even worse.
Worse than what?

Yes, it depends on a compiler extension, one that may or may not become part of the standard one fine day. Still, I'd be interested in using a named literal (for instance this one) without the "using namespace". After all, it is just a function (except that there is some magic that adds the size argument).

Richard Smith

unread,
Jun 16, 2015, 5:42:08 PM6/16/15
to std-pr...@isocpp.org
On Tue, Jun 16, 2015 at 1:12 AM, Roland Bock <rb...@eudoxos.de> wrote:
Boost::Hana provides a user-defined literal that I would like to use to define a compile time string in a header.

See http://ldionne.com/hana/structboost_1_1hana_1_1String.html#ad77f7afff008c2ce15739ad16a8bf0a8

I would really like to say

struct A
{
   using name_t = decltype("sample"_s);

If we remove the (now-redundant) restriction on lambdas in unevaluated operands, you could write:

  using name_t = decltype([] -> decltype(auto) {
    using namespace boost::hana;
    return "sample"_s;
  });

And in today's C++:

  static decltype(auto) name() {
    using namespace boost::hana;
    return "sample"_s;
  }
  using name_t = decltype(name());

Tomasz

unread,
Jun 17, 2015, 1:08:33 AM6/17/15
to std-pr...@isocpp.org


#include <string>

auto hello = "hello"s; //of course not
auto world = "world"std::literals::string_literals::operator""s;
auto any = "any"(std::literals::string_literals::operator""s);
auto ideas = std::literals::string_literals::operator""s("ideas?");


As, the literals namespaces are inline, this could be simplified to use std::opeator""s. However I think that better syntax would be to place the qualification before literal itself, so we would get:

auto hello = "hello"s;
auto world = std::"world"s;
auto any = std::literals::string_literals::"any"s; //If you insist on writing more
and
auto s = boost::hana::"sample"_s;

Having prefixed qualified literal would allow to remove the limittion to use _ in user defined literals, because situation would now be same as for any other entity.

Tomasz

unread,
Jun 17, 2015, 1:16:19 AM6/17/15
to std-pr...@isocpp.org
But, again, what's the point?

To no put arbitrarily restrictions on the suffix name and allow multiple libraries providing same suffixes to be used in single program, which is the thing we use namespace for. For example if I have std::string and mylib::string, then both libraries would be allowed to provide s literal and I would use std::"ala"s to get std::string and mylib::"ala"s to get mylib::string.

Roland Bock

unread,
Jun 17, 2015, 3:05:08 AM6/17/15
to std-pr...@isocpp.org
On 2015-06-17 07:08, Tomasz wrote:


#include <string>

auto hello = "hello"s; //of course not
auto world = "world"std::literals::string_literals::operator""s;
auto any = "any"(std::literals::string_literals::operator""s);
auto ideas = std::literals::string_literals::operator""s("ideas?");


As, the literals namespaces are inline, this could be simplified to use std::opeator""s. However I think that better syntax would be to place the qualification before literal itself, so we would get:
auto hello = "hello"s;
auto world = std::"world"s;
auto any = std::literals::string_literals::"any"s; //If you insist on writing more
and
auto s = boost::hana::"sample"_s;

I would like that very much indeed!

Thus, we could have something like this in a header (without using namespace):

struct A
{
   static auto hello = std::"world"s; // std::string
   static constexpr auto minute = std::60s;     // std::chrono::duration
   static constexpr auto hana = boost::hana::"sample"s; // boost::hana::string
};

That would be quite helpful indeed!



Having prefixed qualified literal would allow to remove the limittion to use _ in user defined literals, because situation would now be same as for any other entity.
+1


Thanks and regards,

Roland

Roland Bock

unread,
Jun 17, 2015, 3:19:27 AM6/17/15
to std-pr...@isocpp.org
On 2015-06-16 23:42, Richard Smith wrote:
On Tue, Jun 16, 2015 at 1:12 AM, Roland Bock <rb...@eudoxos.de> wrote:
Boost::Hana provides a user-defined literal that I would like to use to define a compile time string in a header.

See http://ldionne.com/hana/structboost_1_1hana_1_1String.html#ad77f7afff008c2ce15739ad16a8bf0a8

I would really like to say

struct A
{
   using name_t = decltype("sample"_s);

If we remove the (now-redundant) restriction on lambdas in unevaluated operands, you could write:
Are there plans/proposals to do that? I stumbled over this restriction quite a few times.



  using name_t = decltype([] -> decltype(auto) {
    using namespace boost::hana;
    return "sample"_s;
  });

And in today's C++:

  static decltype(auto) name() {
    using namespace boost::hana;
    return "sample"_s;
  }
  using name_t = decltype(name());

Right, these are possible. But one of the basic ideas of UDLs seems to be brevity. I was hoping for something shorter, more expressive than I have now [1]:

struct alias_t
{
  static constexpr const char _literal[] =  "delta";
  using name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
};

I therefore like Tomasz' suggestion very much:

struct alias_t
{
  using name_t = decltype(::boost::hana::"delta"s);
};

Short and expressive :-)

Best,

Roland


[1] https://github.com/rbock/sqlpp11/blob/master/tests/Sample.h#L14-L17

Richard Smith

unread,
Jun 17, 2015, 2:44:30 PM6/17/15
to std-pr...@isocpp.org
On Wed, Jun 17, 2015 at 12:19 AM, Roland Bock <rb...@eudoxos.de> wrote:
On 2015-06-16 23:42, Richard Smith wrote:
On Tue, Jun 16, 2015 at 1:12 AM, Roland Bock <rb...@eudoxos.de> wrote:
Boost::Hana provides a user-defined literal that I would like to use to define a compile time string in a header.

See http://ldionne.com/hana/structboost_1_1hana_1_1String.html#ad77f7afff008c2ce15739ad16a8bf0a8

I would really like to say

struct A
{
   using name_t = decltype("sample"_s);

If we remove the (now-redundant) restriction on lambdas in unevaluated operands, you could write:
Are there plans/proposals to do that? I stumbled over this restriction quite a few times.

I don't think it's on the core issues list. We discussed it while working on core issue 1607, but I think we thought it would be best handled separately.

Roland Bock

unread,
Jun 17, 2015, 4:37:09 PM6/17/15
to std-pr...@isocpp.org
On 2015-06-17 07:08, Tomasz wrote:
Anybody interested in writing or helping to write a proposal for this? I certainly give it a  try, but it will take some time before I get to it.

Cheers,

Roland

Roland Bock

unread,
Jun 17, 2015, 4:38:47 PM6/17/15
to std-pr...@isocpp.org
On 2015-06-17 20:44, Richard Smith wrote:
On Wed, Jun 17, 2015 at 12:19 AM, Roland Bock <rb...@eudoxos.de> wrote:
On 2015-06-16 23:42, Richard Smith wrote:
On Tue, Jun 16, 2015 at 1:12 AM, Roland Bock <rb...@eudoxos.de> wrote:
Boost::Hana provides a user-defined literal that I would like to use to define a compile time string in a header.

See http://ldionne.com/hana/structboost_1_1hana_1_1String.html#ad77f7afff008c2ce15739ad16a8bf0a8

I would really like to say

struct A
{
   using name_t = decltype("sample"_s);

If we remove the (now-redundant) restriction on lambdas in unevaluated operands, you could write:
Are there plans/proposals to do that? I stumbled over this restriction quite a few times.

I don't think it's on the core issues list. We discussed it while working on core issue 1607, but I think we thought it would be best handled separately.
Can you give me a pointer as to why the restriction is redundant now?

Best,

Roland

Richard Smith

unread,
Jun 17, 2015, 4:46:24 PM6/17/15
to std-pr...@isocpp.org
See core issue 1607. The purpose of the restriction was to avoid lambda-expressions appearing in a signature (so that implementations don't need to implement declaration / statement SFINAE and don't need to mangle them), but it was neither necessary nor sufficient for that. The new rules in core issue 1607 don't need this restriction to implement that intent.

David Rodríguez Ibeas

unread,
Jun 18, 2015, 9:29:02 AM6/18/15
to std-pr...@isocpp.org
Would it make sense to reorder the literal use?

I find this "Hello"std::s more readable than std::"Hello"s. I have the feeling that this would also have less impact on the language (the user defined suffix can be qualified, vs. having to define qualified-literals), it also places the value (which I imagine more important), rather than having to visually scan for the literal inside of the <namespace::><literal><suffix> sequence; and it places the suffix together with the namespace that needs to be checked...

--

Arthur O'Dwyer

unread,
Jun 18, 2015, 8:21:54 PM6/18/15
to std-pr...@isocpp.org, dib...@ieee.org
YMMV; I find std::"Hello"s to be more readable. (Intuitively: std::"Hello"s is a std::string. The prefix remains a prefix, and doesn't switch into an internal position.)
Also, I feel like there would be a potential ambiguity with e.g. "Hello"a::b — is that the b belonging to "Hello"a, or is it "Hello"b evaluated with respect to the a namespace? (Notice that there may also be a member b of the a namespace, which is completely unrelated.) At the moment I think it's impossible to create an actual grammatical ambiguity there, but it feels dangerous.

On the other hand, consider the attempt to create an X::wstring via the expression X::LR"(Hello)"s (respectively LR"(Hello)"X::s). How does this interact with the declaration of a variable named X::LR (respectively X::s)?

Then consider the parsing nightmare that is units::42m resp. 42units::m. (Those expressions' respective readability strikes me as a good argument in favor of Roland's units::42m syntax and against David's alternative suggestion.)

User-defined literals are a mess added on top of the pre-existing mess of literal prefixes and suffixes, and perhaps the best thing to do is just stay far away from them...?

Richard Smith

unread,
Jun 18, 2015, 9:04:09 PM6/18/15
to std-pr...@isocpp.org, dib...@ieee.org
On Thu, Jun 18, 2015 at 5:21 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
YMMV; I find std::"Hello"s to be more readable. (Intuitively: std::"Hello"s is a std::string. The prefix remains a prefix, and doesn't switch into an internal position.)
Also, I feel like there would be a potential ambiguity with e.g. "Hello"a::b — is that the b belonging to "Hello"a, or is it "Hello"b evaluated with respect to the a namespace? (Notice that there may also be a member b of the a namespace, which is completely unrelated.) At the moment I think it's impossible to create an actual grammatical ambiguity there, but it feels dangerous.

The nested-name-specifier-after-literal form is also unusable for various kinds of ud-suffix. For instance:

  std::complex<float> x = 1.0std::if; // error, 'if' is a keyword
  my::filesize = 33my::_MB; // error, '_MB' is reserved

Putting the nested-name-specifier before the user-defined-literal token seems like the better choice to me.
 
On the other hand, consider the attempt to create an X::wstring via the expression X::LR"(Hello)"s (respectively LR"(Hello)"X::s). How does this interact with the declaration of a variable named X::LR (respectively X::s)?

I don't think this is any different from the existing situation if you wrote LR"(Hello)"s inside namespace X: you get a raw string literal token. I think this works fine with either approach.
 
Then consider the parsing nightmare that is units::42m resp. 42units::m. (Those expressions' respective readability strikes me as a good argument in favor of Roland's units::42m syntax and against David's alternative suggestion.)

I too find the prefix form more readable.

David Krauss

unread,
Jun 18, 2015, 10:08:02 PM6/18/15
to std-pr...@isocpp.org

On 2015–06–19, at 9:04 AM, Richard Smith <ric...@metafoo.co.uk> wrote:

Putting the nested-name-specifier before the user-defined-literal token seems like the better choice to me.

That still demands that translation phase 6, merging adjacent string literals, can recognize the qualifiers. Currently that step can be done together with preprocessing.

Richard Smith

unread,
Jun 18, 2015, 11:39:32 PM6/18/15
to std-pr...@isocpp.org
I don't think that's absolutely necessary; allowing std::"foo"s "bar" (or std::"foo" "bar"s) but not std::"foo"s std::"bar"s doesn't seem like a disaster to me, and seems better than moving string literal concatenation into phase 7. (This is another reason to prefer prefix over suffix; the same thing doesn't work out too well for the suffix form.)

But I agree this is a problem, and for me at least it weighs somewhat against the proposed change.

Tomasz

unread,
Jun 19, 2015, 12:44:03 AM6/19/15
to std-pr...@isocpp.org, dib...@ieee.org


W dniu piątek, 19 czerwca 2015 02:21:54 UTC+2 użytkownik Arthur O'Dwyer napisał:

User-defined literals are a mess added on top of the pre-existing mess of literal prefixes and suffixes, and perhaps the best thing to do is just stay far away from them...?

I do not agree with that point. As I understand user defined literals was developed mainly for the library writers to provide support equivalent as one for build-in types for the types that they provide. However in the current form they are not really usable - the client of the multiple libraries are unable to resolve ambiguity caused by having same suffix in multiple used libraries. And we have only avoided the problem by reserving names that does not start "_" for standard library - such solution is not viable for other libraries, because if they decided to choose a short prefix then there is no guarantee that other library will not use it, and using long unambiguous prefixes defeat the point of using them, and also put as again in pre-namespace world. As C++ aims to be language for witting libraries and does not provide standard library with everything in it, then we should provide equal support for other libraries like for standard one, including support for reasonable (short) user defined literals.

Also, the user cannot simply invoke operator"" literal instead of using 123litterals, because they will need to know which form is used:
operator"" literal(123);
operator"" literal("123");
operator"" literal<'1', '2', '3'>(); //The 3rd form is hardly to be considered usable outside of automatic compiler calls.

Arthur O'Dwyer

unread,
Jun 19, 2015, 1:20:03 AM6/19/15
to std-pr...@isocpp.org
On Thu, Jun 18, 2015 at 9:44 PM, Tomasz <toma...@gmail.com> wrote:
W dniu piątek, 19 czerwca 2015 02:21:54 UTC+2 użytkownik Arthur O'Dwyer napisał:

User-defined literals are a mess added on top of the pre-existing mess of literal prefixes and suffixes, and perhaps the best thing to do is just stay far away from them...?

I do not agree with that point.
[...] However in the current form they are not really usable [...] unable to resolve ambiguity [...] we have only avoided the problem by reserving names that does not start "_" for standard library - such solution is not viable for other libraries [...] the user cannot simply invoke operator"" literal instead of using 123litterals, because they will need to know which form is used:

operator"" literal(123);
operator"" literal("123");
operator"" literal<'1', '2', '3'>(); //The 3rd form is hardly to be considered usable outside of automatic compiler calls.

It sounds to me as if you do agree with my point. :D

Here's a thought experiment: What if, instead of having to write something like std::"Hello"s to construct a string, we could use the more functional-style notation std::s("Hello")? Such "functional-notation literals" could reuse the existing rules for overload resolution (we could get rid of the three different forms of operator"") and wouldn't lead us into any weird corner cases in the grammar. We could even exploit function overloading to make std::s(42) mean "42 seconds" and std::s("Hello") mean "a string with value Hello"... although from the programmer's point of view it might be preferable in practice to disambiguate by spelling out the words — std::seconds(42) and std::string("Hello") respectively — so we'd like to make that possible, too.
Now what if I told you that the capability for this elegant form of literal notation has existed in C++ since 1998?! :)

I'll admit, UDLs did make it possible for 42_c to mean std::integral_constant<int,42>{}; that is, UDLs are pretty much the only way (besides a macro) to wrap a value in angle brackets without actually writing a pair of angle brackets in the code. But if we'd started with that goal actually in mind, would we have settled on UDLs as the right way to achieve it?

–Arthur

Tomasz Kamiński

unread,
Jun 19, 2015, 5:14:37 AM6/19/15
to std-pr...@isocpp.org
Using funciton syntax namespace::literal(value), i.e. std::s("Hello") will cause confilicts with the objects/functions named as literal declared in the namespace. Notice that you currently can define both function or object named s and operator""s in single namespace.

--

---
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/hAnVRTlsQZY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

Tomasz Kamiński

unread,
Jun 19, 2015, 5:23:11 AM6/19/15
to std-pr...@isocpp.org
Using the literal is only way to intialize variable class integer class (like big int) with arbitrally large number. Using bigint("123456767435343453454") requires parsing at runtime, and bigint(123456767435343453454) rerquires that the given number will fit into largest integer type, i.e. defeat purpose of using bigint.

David Krauss

unread,
Jun 19, 2015, 8:05:19 AM6/19/15
to std-pr...@isocpp.org
Maybe the problem is that breaking a token into a character sequence is a fundamental capability that shouldn’t be tied to the special UDL syntax.

Why not let make_bigint< "1234" >() do it? (And, on the way, allow bigintlib::operator "" _big< "1234" >() as equivalent to 1234_big.)

Tomasz Kamiński

unread,
Jun 19, 2015, 9:04:21 AM6/19/15
to std-pr...@isocpp.org
I do not consider the make_bigint< "1234" >(), to be as readable and user friendly as 1234_big, which I consider as argument for having user-defined literals in the language. But I belive that requires to support some form of qualified literals type, to allow library creators to provide resonable literal for thier types, without causing ambiguity problems for users that combines multiple libraries in single program. Reserving certain preffix for suffix is not an scalable option.

Sam Kellett

unread,
Jun 19, 2015, 9:24:55 AM6/19/15
to std-pr...@isocpp.org
On 19 June 2015 at 14:04, Tomasz Kamiński <toma...@gmail.com> wrote:
I do not consider the make_bigint< "1234" >(), to be as readable and user friendly as 1234_big, which I consider as argument for having user-defined literals in the language. But I belive that requires to support some form of qualified literals type, to allow library creators to provide resonable literal for thier types, without causing ambiguity problems for users that combines multiple libraries in single program. Reserving certain preffix for suffix is not an scalable option.


This is just an idea that popped into my head, but would it be reasonable to split up the tokens of a literal so that the namespace comes in between the UDL prefix and the specified suffix?

For example:

    "delta"_boost::hana::s

    namespace hana = boost::hana;
    "delta"_hana::s

    1234_bigintlib::big

I dunno, seems a more logical place for the namespace to go rather than the beginning (like, where else does that happen?!).

Roland Bock

unread,
Jun 19, 2015, 9:36:40 AM6/19/15
to std-pr...@isocpp.org
On 2015-06-19 07:20, Arthur O'Dwyer wrote:
On Thu, Jun 18, 2015 at 9:44 PM, Tomasz <toma...@gmail.com> wrote:
W dniu piątek, 19 czerwca 2015 02:21:54 UTC+2 użytkownik Arthur O'Dwyer napisał:

User-defined literals are a mess added on top of the pre-existing mess of literal prefixes and suffixes, and perhaps the best thing to do is just stay far away from them...?

I do not agree with that point.
[...] However in the current form they are not really usable [...] unable to resolve ambiguity [...] we have only avoided the problem by reserving names that does not start "_" for standard library - such solution is not viable for other libraries [...] the user cannot simply invoke operator"" literal instead of using 123litterals, because they will need to know which form is used:
operator"" literal(123);
operator"" literal("123");
operator"" literal<'1', '2', '3'>(); //The 3rd form is hardly to be considered usable outside of automatic compiler calls.

It sounds to me as if you do agree with my point. :D

Here's a thought experiment: What if, instead of having to write something like std::"Hello"s to construct a string, we could use the more functional-style notation std::s("Hello")? Such "functional-notation literals" could reuse the existing rules for overload resolution (we could get rid of the three different forms of operator"") and wouldn't lead us into any weird corner cases in the grammar. We could even exploit function overloading to make std::s(42) mean "42 seconds" and std::s("Hello") mean "a string with value Hello"... although from the programmer's point of view it might be preferable in practice to disambiguate by spelling out the words — std::seconds(42) and std::string("Hello") respectively — so we'd like to make that possible, too.
Now what if I told you that the capability for this elegant form of literal notation has existed in C++ since 1998?! :)
The difference being that in case of a string UDL, the compiler adds a second argument (the size).



I'll admit, UDLs did make it possible for 42_c to mean std::integral_constant<int,42>{}; that is, UDLs are pretty much the only way (besides a macro) to wrap a value in angle brackets without actually writing a pair of angle brackets in the code. But if we'd started with that goal actually in mind, would we have settled on UDLs as the right way to achieve it?

Considering that my starting point was boost::hana::operator""_s which turns "delta" into boost::hana::string<'d','e','l','t','a'>{}, this certainly is a very valid point :-)

For that use case I'd be happy with anything that I could use like this, too:

struct A
{
   static constexpr auto name = make_compile_time_string("whatever");
};

or

struct B
{
   using name_t = make_compile_time_string<"whatever">;
};

make_compile_time_string should NOT be a macro, of course :-)


Best,

Roland

Tomasz

unread,
Jun 19, 2015, 10:37:59 AM6/19/15
to std-pr...@isocpp.org

W dniu piątek, 19 czerwca 2015 15:24:55 UTC+2 użytkownik Sam Kellett napisał:
I dunno, seems a more logical place for the namespace to go rather than the beginning (like, where else does that happen?!).

If I have function in the namespace, and I want to call it, I place the namespace before its name (std::begin(c)). If I have constant or variable, I also place the namespace before it (std::placeholders::_1), so then if I have a object created using literal ("hello"s), then I should place namespace before it to qualify (std::"hello"s). There is no entity named s in the std::literals::string_literals namespace.

Max Truxa

unread,
Jun 22, 2015, 2:16:44 AM6/22/15
to std-pr...@isocpp.org
std::""s is just illogical. Even going by your own logic. It's s that is in std not ""s.

Tomasz

unread,
Jun 22, 2015, 3:19:00 AM6/22/15
to std-pr...@isocpp.org

W dniu poniedziałek, 22 czerwca 2015 08:16:44 UTC+2 użytkownik Max Truxa napisał:
std::""s is just illogical. Even going by your own logic. It's s that is in std not ""s.

We define operator""s in the namespace std, not the s itself. Please remember that we allow operator ""if to be defined, while there cannot be entity named if in any namespace. So the syntax std::if would be incompatible with complex literals. the std::""s, suggest that we want tu use operator ""s from std::namespace.

David Krauss

unread,
Jun 22, 2015, 3:48:13 AM6/22/15
to std-pr...@isocpp.org
On 2015–06–22, at 3:18 PM, Tomasz <toma...@gmail.com> wrote:

We define operator""s in the namespace std, not the s itself. Please remember that we allow operator ""if to be defined

More precisely, operator""if is defined in [complex.literals] §26.4.10/4. Users can’t declare things like that, though, because UDL names not beginning with an underscore are reserved to the standard.

, while there cannot be entity named if in any namespace. So the syntax std::if would be incompatible with complex literals. the std::""s, suggest that we want tu use operator ""s from std::namespace.

There’s no grammatical ambiguity in the case of if, because that keyword can only appear at the beginning of a statement. The only keyword I can think of that can follow :: is template. It’s ugly, though.

UDLs are supposed to provide convenience. Is it really worth reconciling these tiny identifiers with namespace qualification? Regardless of what a parser can handle, awkwardness negates their purpose. Maybe it’s better just to ensure that there’s always a qualification-friendly ordinary function call to accomplish the same task.

David Krauss

unread,
Jun 22, 2015, 4:15:41 AM6/22/15
to std-pr...@isocpp.org

On 2015–06–22, at 3:47 PM, David Krauss <pot...@mac.com> wrote:

The only keyword I can think of that can follow :: is template.

Oh, and operator. Who could forget operator "" operator. Let it return a callable type and you can have R"operator()operator"operator().

Also, some implementations also accept the alternative spellings of punctuation, such as or. The standard is a bit ambiguous about whether these form UDLs, since they are forbidden from being identifiers, but only as long as they form separate tokens. The intent is probably that they should be reserved.

Point is, qualified lookup is equally hacked whether you allow a literal token or a keyword on the right-hand side.

Myriachan

unread,
Jun 24, 2015, 12:47:45 AM6/24/15
to std-pr...@isocpp.org, pot...@mac.com
On Monday, June 22, 2015 at 12:48:13 AM UTC-7, David Krauss wrote:
On 2015–06–22, at 3:18 PM, Tomasz <toma...@gmail.com> wrote:

We define operator""s in the namespace std, not the s itself. Please remember that we allow operator ""if to be defined

More precisely, operator""if is defined in [complex.literals] §26.4.10/4. Users can’t declare things like that, though, because UDL names not beginning with an underscore are reserved to the standard.

 
And Clang enforces this rule as an error >.<



On Thursday, June 18, 2015 at 9:44:03 PM UTC-7, Tomasz wrote:
operator"" literal<'1', '2', '3'>(); //The 3rd form is hardly to be considered usable outside of automatic compiler calls.
 
Although orthogonal to this discussion, I wish we were allowed to pass literal strings or constant-expression char arrays to variadic char templates.  It'd be a neat solution to the decades-long annoyance that literal strings can't be template parameters.

Melissa

David Krauss

unread,
Jun 24, 2015, 1:50:53 AM6/24/15
to std-pr...@isocpp.org, Myriachan

On 2015–06–24, at 12:47 PM, Myriachan <myri...@gmail.com> wrote:

Although orthogonal to this discussion, I wish we were allowed to pass literal strings or constant-expression char arrays to variadic char templates.  It'd be a neat solution to the decades-long annoyance that literal strings can't be template parameters.

Not orthogonal, I suggested that earlier.

Another approach, perhaps less intrusive to template parameter passing, is to let the string-literal/array argument initialize a template type parameter with a variadic character list in a partial specialization.

template< char ... c >
struct narrow_string;

template< char32_t ... c >
struct wide_string;

template< typename str >
struct my_string_metafn;

template< char ... c >
struct my_string_metafn< narrow_string < c ... > > { … };

template< char32_t ... c >
struct my_string_metafn< wide_string < c ... > > { … };

my_string_metafn< "hello" >::type foo;
my_string_metafn< U"hello" >::type bar;

This provides for 1-to-1 mapping of arguments to parameters and encourages encapsulation of variadic lists.

This is also similar to the pure-library approach of defining operator""cs for compile-time strings, and then always use those strings as the starting point. This was the direction things were going at Urbana. Anyone who wants to let a library do string transformations will need to say using std::operator""cs, and pass them as function arguments or through decltype. Unless the proposals get more ambitious, it seems unlikely for compile-time strings to be tied closer to the core language for now. But the avenue is still open.

Roland Bock

unread,
Jun 24, 2015, 4:07:12 AM6/24/15
to std-pr...@isocpp.org
On 2015-06-24 07:50, David Krauss wrote:

On 2015–06–24, at 12:47 PM, Myriachan <myri...@gmail.com> wrote:

Although orthogonal to this discussion, I wish we were allowed to pass literal strings or constant-expression char arrays to variadic char templates.  It'd be a neat solution to the decades-long annoyance that literal strings can't be template parameters.

Not orthogonal, I suggested that earlier.
Anything "official" / links? How was the feedback?



Another approach, perhaps less intrusive to template parameter passing, is to let the string-literal/array argument initialize a template type parameter with a variadic character list in a partial specialization.

template< char ... c >
struct narrow_string;

template< char32_t ... c >
struct wide_string;

template< typename str >
struct my_string_metafn;

template< char ... c >
struct my_string_metafn< narrow_string < c ... > > { … };

template< char32_t ... c >
struct my_string_metafn< wide_string < c ... > > { … };

my_string_metafn< "hello" >::type foo;
my_string_metafn< U"hello" >::type bar;

This provides for 1-to-1 mapping of arguments to parameters and encourages encapsulation of variadic lists.
Not sure if I understand this correctly. Wouldn't the compiler have to turn "hello" into std::narrow_string<'h','e','l','l','o'> automatically here?



This is also similar to the pure-library approach of defining operator""cs for compile-time strings, and then always use those strings as the starting point. This was the direction things were going at Urbana. Anyone who wants to let a library do string transformations will need to say using std::operator""cs, and pass them as function arguments or through decltype.
And then we're back to square one, if I want to do this in a header and initialize a static constexpr member of a class... :-(



Unless the proposals get more ambitious, it seems unlikely for compile-time strings to be tied closer to the core language for now. But the avenue is still open.

Is there a proposal for std::operator""cs already?

Best,

Roland

David Krauss

unread,
Jun 24, 2015, 4:41:22 AM6/24/15
to std-pr...@isocpp.org
On 2015–06–24, at 4:07 PM, Roland Bock <rb...@eudoxos.de> wrote:

On 2015-06-24 07:50, David Krauss wrote:

On 2015–06–24, at 12:47 PM, Myriachan <myri...@gmail.com> wrote:

Although orthogonal to this discussion, I wish we were allowed to pass literal strings or constant-expression char arrays to variadic char templates.  It'd be a neat solution to the decades-long annoyance that literal strings can't be template parameters.

Not orthogonal, I suggested that earlier.
Anything "official" / links? How was the feedback?

I just mean, a few messages earlier in this thread. “Why not let make_bigint< "1234" >() do it?” That’s all.

Not sure if I understand this correctly. Wouldn't the compiler have to turn "hello" into std::narrow_string<'h','e','l','l','o'> automatically here?

Yes, but I think that’s better than turning "hello" into 'h','e','l','l','o'. Not least because we seem to be dropping the NUL termination, which tends to suggest that the sequence should be inside something. (This is also the behavior of literal operator templates. It looks like a strike against named char arrays.)

And then we're back to square one, if I want to do this in a header and initialize a static constexpr member of a class... :-(

constexpr lambdas look pretty likely for C++17.

Is there a proposal for std::operator""cs already?

There’s N4121 which called it operator""sl, and N3933 which was presented but missed the deadline. It was very similar.

Reviewing N4121, it doesn’t encode the string in the type. You can still unpack it using an index_sequence, though.

Roland Bock

unread,
Jun 24, 2015, 5:24:22 AM6/24/15
to std-pr...@isocpp.org
On 2015-06-24 10:41, David Krauss wrote:

On 2015–06–24, at 4:07 PM, Roland Bock <rb...@eudoxos.de> wrote:

On 2015-06-24 07:50, David Krauss wrote:

On 2015–06–24, at 12:47 PM, Myriachan <myri...@gmail.com> wrote:

Although orthogonal to this discussion, I wish we were allowed to pass literal strings or constant-expression char arrays to variadic char templates.  It'd be a neat solution to the decades-long annoyance that literal strings can't be template parameters.

Not orthogonal, I suggested that earlier.
Anything "official" / links? How was the feedback?

I just mean, a few messages earlier in this thread. “Why not let make_bigint< "1234" >() do it?” That’s all.
Ah, I misread that somehow.



Not sure if I understand this correctly. Wouldn't the compiler have to turn "hello" into std::narrow_string<'h','e','l','l','o'> automatically here?

Yes, but I think that’s better than turning "hello" into 'h','e','l','l','o'. Not least because we seem to be dropping the NUL termination, which tends to suggest that the sequence should be inside something. (This is also the behavior of literal operator templates. It looks like a strike against named char arrays.)
On the other hand, if the compile turned hello" into 'h','e','l','l','o', the developer could choose between passing "hello" into something that expects a parameter pack of chars or packing it into a type for partial specialization.

namespace std
{

   template< char ... c >
   struct narrow_string;

   template< char32_t ... c >
   struct wide_string;
}

namespace my
{
   template<char...c> compile_time_string;
   template<typename T> sample;
}

int main()
{
   auto cs = my::compile_time_string<"hello">;
   auto s = my::sample<std::narrow_string<"hello">>;
}

Personally I would prefer having that choice, rather than having to transform narrow_string into my::compile_time_string.



And then we're back to square one, if I want to do this in a header and initialize a static constexpr member of a class... :-(

constexpr lambdas look pretty likely for C++17.
That would certainly help :-)



Is there a proposal for std::operator""cs already?

There’s N4121 which called it operator""sl, and N3933 which was presented but missed the deadline. It was very similar.

Reviewing N4121, it doesn’t encode the string in the type. You can still unpack it using an index_sequence, though.
Thanks for the pointers, will look into those.

Reply all
Reply to author
Forward
0 new messages