Doc. No.: | N4236 |
---|---|
Date: | 2014-10-10 |
Project: | Programming Language C++, Reflection Study Group |
Reply To: | Michael Price <michael.b.price.dev@gmail.com> |
Proposes a compile-time string library type template, std::basic_string_literal
, a user-defined literal (UDL) to facilitate instantiation of said template, as well as a language extension to allow implementation of the specified UDL.
The type model of literal strings in C++ was largely inherited directly from C, with a few minor tweaks throughout the years (such as restricting conversions to non-const char*
). The inclusion of the standard library's std::basic_string
template solves many of the problems with the usability of string literals by providing a rich interface for accessing, searching, and manipulating the value of the string. There are many places where std::basic_string
or const char*
both fall short.
// Concatenation
//
auto x1 = "Hello" + ", " + "World!"; // Error!
auto x2 = std::string("Hello") + ", " + "World!"; // Valid, but odd. Also runtime cost.
auto x3 = "Hello" + std::string(", ") + "World!"; // Error!
auto x4 = "Hello" ", " "World!"; // Valid, but...
auto conjunction = std::string(", ");
auto x5 = "Hello" conjuction "World!"; // Error!
// Generic Programming
//
template <typename T>
typename T::size_type find(T t, typename T::value_type q)
{
return t.find(q);
}
auto s1 = std::string("One");
auto s2 = "Two";
find(s1, 'n'); // Okay
find(s2, 'w'); // Error!
find(std::string(s2), 'w'); // Okay, but come on!
// Template Metaprogramming
//
template <typename T> struct metaprogram { /* ... */ };
metaprogram<"Hello, World!"> m1; // Error!
metaprogram<std::string("Hello, World!")> m2; // What does this even mean!
metaprogram<decltype("Hello, World!")> m3; // Not what you wanted!
metaprogram<decltype(std::string("Hello, World!"))> m4; // Also not what you wanted!
metaprogram<boost::mpl::string<'Hell','o, W','orld', '!'>> m5; // There we go! But oh my...
metaprogram<_S("Hello, World!")> m6; // Don't look behind the curtain (see reference [1])
We propose a new library template, std::basic_string_literal
, and a UDL to solve the problems with the previous example. Application of the template to the problems above is shown below. An implementation of this template can be found at [2].
// Concatenation
//
constexpr auto x1 = "Hello"S + ", "S + "World!"S; // Valid, no runtime cost
constexpr auto conjunction = ", "S;
constexpr auto x5 = "Hello"S + conjuction + "World!"S; // Valid, no runtime cost
// Generic Programming
//
template <typename T>
constexpr typename T::size_type find(T t, typename T::value_type q)
{
return t.find(q);
}
auto s1 = std::string("One");
constexpr auto s2 = "Two"S;
find(s1, 'n'); // Okay
find(s2, 'w'); // Valid, no runtime cost
// Template Metaprogramming
//
template <typename T> struct metaprogram { /* ... */ };
metaprogram<decltype("Hello, World!"S)> m1; // Valid, although a bit unfortunate
We believe that this template, and the mechanisms supporting it, could have many other application which we have not listed here. See N3599 [2] for such examples.
This proposal depends on user-defined literals which were introduced in C++11. It also requires an extension of the UDL operator template mechanism to apply to string literals in addition to numeric literals. It may also require extension of the basic_string
and basic_string_view
templates in order to provide the best integration with the standard library.
The design and wording for the UDL operator template extension has been taken from N3599 [3]. At the suggestion of that paper's author, Richard Smith, I have clarified that C is cv-unqualified. There are additional rationales in that paper for the usefulness of that particular extension.
The design of the proposed compile-time string template is meant to include the const
portions of the std::basic_string
template as closely as possible, while also adding a couple of additional capabilities. The proposed UDL that would construct these new types uses an S
(uppercase), whereas the UDL for std::basic_string
uses an s
(lowercase); this was a conscious design decision.
We have purposefully made the only constructor of basic_string_literal
both private
and constexpr
. Creation is only allowed via the supplied constexpr
UDL in order to prevent any runtime instances of the instantiated template.
There are a couple of design alternatives that were identified, but are not explored in this paper. One design would forego the extension to UDL operator templates in favor of the cooked form of the UDL. This could allow a library-only solution with possibly improved efficiency, but might restrict the possible uses (see N4121 [4]). Another alternative would take the approach that lambdas and/or std::initializer_list
took, which would result in "compiler magic" to provide the appropriate type. The author feels that the proposal in this paper is a middle-ground between these other approaches.
Disclaimer: This technical specification may not be complete and is likely fraught with errors. It will need to be reviewed carefully and updated to be in proper form for inclusion in the standard.
The term of art literal operator template is split into two terms, numeric literal operator template and string literal operator template. The term literal operator template is retained and refers to either form.
Replace literal operator template
with numeric literal operator
template
in [lex.ext] (2.14.8)/3 and [lex.ext] (2.14.8)/4:
[...] Otherwise, S shall contain a raw literal operator or a numeric literal operator template (13.5.8) but not both. [...] Otherwise (S contains a numeric literal operator template), L is treated as a call of the form [...]
Change in [lex.ext] (2.14.8)/5:
If L is a user-defined-string-literal, let C be the cv-unqualified element type of the string literal as determined by its encoding-prefix, let str be the literal without its ud-suffix, and let len be the number of code units in str (i.e., its length excluding the terminating null character). If S contains a literal operator with parameter typesconst C *
andstd::size_t
, theTheliteral L is treated as a call of the formoperator "" X(str, len)
Otherwise, S shall contain a string literal operator template (13.5.8), and L is treated as a call of the form
operator "" X<C, e's1', e's2', ... e'sk'>()
where e is empty when the encoding-prefix isu8
and is otherwise the encoding-prefix of the string literal, and str contains the sequence of code units s1s2...sk (excluding the terminating null character).
Change in [over.literal] (13.5.8)/5:
The declaration of a literal operator template shall have an empty parameter-declaration-clause and its template-parameter-list shall haveA numeric literal operator template is a literal operator template whose template-parameter-list has a single template-parameter that is a non-type template parameter pack (14.5.3) with element typechar
. A string literal operator template is a literal operator template whose template-parameter-list comprises a type template-parameter C followed by a non-type template parameter pack with element type C. The declaration of a literal operator template shall have an empty parameter-declaration-clause and shall declare either a numeric literal operator template or a string literal operator template.
Edit [string.classes] (21.3)/1 as follows:
The header<string>
defines thebasic_string
class template for manipulating varying-length sequences of char-like objects and four typedefs,string
,u16string
,u32string
, andwstring
, that name the specializationsbasic_string<char>
,basic_string<char16_t>
,basic_string<char32_t>
, andbasic_string<wchar_t>
, respectively. The header<string>
also defines thebasic_string_literal
class template for manipulating compile-time sequences of char-like objects and four typedefs,string_literal
,u16string_literal
,u32string_literal
, andwstring_literal
, that name the specializationsbasic_string_literal<char>
,basic_string_literal<char16_t>
,basic_string_literal<char32_t>
, andbasic_string_literal<wchar_t>
, respectively.Header
<string>
synopsis
#include <initializer_list> namespace std { // 21.2, character traits: template<class charT> struct char_traits; template <> struct char_traits<char>; template <> struct char_traits<char16_t>; template <> struct char_traits<wchar_t>; // 21.4, basic_string: template<class charT>, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string; // 21.5, basic_string_literal: template<class charT>, class traits = char_traits<charT>, charT... Chars> class basic_string_literal; template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const basic_string<charT,traits,Allocator>& lhs, basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(basic_string<charT,traits,Allocator>& lhs, basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const charT* lhs, basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(charT lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(charT lhs, basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(const basic_string<charT,traits,Allocator>& lhs, charT rhs); template<class charT, class traits, class Allocator> basic_string<charT,traits,Allocator> operator+(basic_string<charT,traits,Allocator>& lhs, charT rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars>; constexpr basic_string_literal<charT,traits,LhsChars...,RhsChars...> operator+ (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; basic_string<charT,traits,Allocator> operator+ (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; basic_string<charT,traits,Allocator> operator+ (const basic_string_literal<charT,traits,LhsChars...>& lhs, basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; basic_string<charT,traits,Allocator> operator+ (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; basic_string<charT,traits,Allocator> operator+ (const basic_string_literal<charT,traits,LhsChars...>& lhs, charT rhs); template<class charT, class traits, class Allocator, charT... RhsChars>; basic_string<charT,traits,Allocator> operator+ (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,LhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... RhsChars>; basic_string<charT,traits,Allocator> operator+ (basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,LhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator==(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator==(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> bool operator==(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars>; constexpr bool operator== (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; bool operator== (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars>; bool operator== (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, class Allocator, charT... RhsChars>; bool operator== (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... RhsChars>; bool operator== (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator!=(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator!=(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, class Allocator> bool operator!=(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars>; constexpr bool operator!= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars>; bool operator!= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars>; bool operator!= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, class Allocator, charT... RhsChars>; bool operator!= (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... RhsChars>; bool operator!= (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator< (const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator< (const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> bool operator< (const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars> constexpr bool operator< (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars> bool operator< (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator, charT... RhsChars> bool operator< (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... LhsChars> bool operator< (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, charT... RhsChars> bool operator< (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator> (const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator> (const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> bool operator> (const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars> constexpr bool operator> (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars> bool operator> (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator, charT... RhsChars> bool operator> (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... LhsChars> bool operator> (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, charT... RhsChars> bool operator> (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator<= (const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator<= (const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> bool operator<= (const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars> constexpr bool operator<= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars> bool operator<= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator, charT... RhsChars> bool operator<= (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... LhsChars> bool operator<= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, charT... RhsChars> bool operator<= (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator> bool operator>= (const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator> bool operator>= (const basic_string<charT,traits,Allocator>& lhs, const charT* rhs); template<class charT, class traits, class Allocator> bool operator>= (const charT* lhs, const basic_string<charT,traits,Allocator>& rhs); template<class charT, class traits, charT... LhsChars, charT... RhsChars> constexpr bool operator>= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, class Allocator, charT... LhsChars> bool operator>= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; template<class charT, class traits, class Allocator, charT... RhsChars> bool operator>= (const basic_string<charT,traits,Allocator>& lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); template<class charT, class traits, charT... LhsChars> bool operator>= (const basic_string_literal<charT,traits,LhsChars...>& lhs, const charT* rhs); template<class charT, class traits, charT... RhsChars> bool operator>= (const charT* lhs, const basic_string_literal<charT,traits,RhsChars...>& rhs); // 21.4.8.8, swap: template<class charT, class traits, class Allocator> void swap(basic_string<charT,traits,Allocator>& lhs, basic_string<charT,traits,Allocator>& rhs); // 21.4.8.9, inserters and extractors: template<class charT, class traits, class Allocator> basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>& is, basic_string<charT,traits,Allocator>& str); template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str); template<class charT, class traits, charT... Chars> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string_literal<charT,traits,Chars...>& str); template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>& is, basic_string<charT,traits,Allocator>& str, charT delim); template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>&& is, basic_string<charT,traits,Allocator>& str, charT delim); template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>& is, basic_string<charT,traits,Allocator>& str); template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>&& is, basic_string<charT,traits,Allocator>& str); }
Insert as 21.5
template <typename charT, charT... Chars> class basic_string_literal; template <typename charT, charT... Chars> constexpr basic_string_literal<charT, Chars...> operator""S(); template <typename charT, charT... Chars> class basic_string_literal { friend constexpr basic_string_literal operator""S<charT, HeadChar, TailChars...> (); public: static constexpr const charT data_[] = { HeadChar, TailChars..., '\0' }; private: constexpr basic_string_literal() = default; public: using value_type = charT; using size_type = std::size_t; using difference_type = std::size_t; using tail_type = basic_string_literal<charT>; // Size-related functions constexpr size_type size () const; constexpr size_type length () const; constexpr bool empty () const; // Element accessor functions constexpr charT operator[] (size_type pos) const; template <size_type Index> constexpr charT at () const; constexpr charT at (size_type pos) const; constexpr charT back () const; constexpr charT front () const; // Search functions template <charT... OtherChars> constexpr size_type find (const basic_string_literal<charT, OtherChars...>& str, size_type pos = 0) const; constexpr size_type find (const charT* s, size_type pos, size_type count) const; constexpr size_type find (const charT* s, size_type pos = 0) const; constexpr size_type find (charT ch, size_type pos = 0) const; template <charT... OtherChars> constexpr size_type rfind (const basic_string_literal<charT, OtherChars...>& str, std::size_t pos = sizeof...(Chars)) const; constexpr size_type rfind (const charT* s, size_type pos, size_type count) const; constexpr size_type rfind (const charT* s, size_type pos = sizeof...(Chars)) const; constexpr size_type rfind (charT ch, size_t pos = sizeof...(Chars)) const; template <charT... OtherChars> constexpr size_type find_first_of (const basic_string_literal<charT, OtherChars...>& str, size_type pos = 0) const; constexpr size_type find_first_of (const charT* s, size_type pos, size_type count) const; constexpr size_type find_first_of (const charT* s, size_type pos = 0) const; constexpr size_type find_first_of (charT ch, size_type pos = 0) const; template <charT... OtherChars> constexpr size_type find_first_not_of (const basic_string_literal<charT, OtherChars...>& str, size_type pos = 0) const; constexpr size_type find_first_not_of (const charT* s, size_type pos, size_type count) const; constexpr size_type find_first_not_of (const charT* s, size_type pos = 0) const; constexpr size_type find_first_not_of (charT ch, size_type pos = 0) const; template <charT... OtherChars> constexpr size_type find_last_of (const basic_string_literal<charT, OtherChars...>& str, size_type pos = sizeof...(Chars)) const; constexpr size_type find_last_of (const charT* s, size_type pos, size_type count) const; constexpr size_type find_last_of (const charT* s, size_type pos = sizeof...(Chars)) const; constexpr size_type find_last_of (charT ch, size_t pos = sizeof...(Chars)) const; template <charT... OtherChars> constexpr size_type find_last_not_of (const basic_string_literal<charT, OtherChars...>& str, size_type pos = sizeof...(Chars)) const; constexpr size_type find_last_not_of (const charT* s, size_type pos, size_type count) const; constexpr size_type find_last_not_of (const charT* s, size_type pos = sizeof...(Chars)) const; constexpr size_type find_last_not_of (charT ch, size_t pos = sizeof...(Chars)) const; // Comparison functions template <charT... OtherChars>; constexpr int compare (const basic_string_literal<charT, OtherChars...> & other) const; constexpr int compare (const basic_string& str) const; constexpr int compare (size_type pos1, size_type count1, const basic_string& str) const; constexpr int compare (size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2) const; constexpr int compare (const charT* s) const; constexpr int compare (size_type pos1, size_type count1, const charT* s) const; constexpr int compare (size_type pos1, size_type count1, const charT* s, size_type count2) const; // Conversion functions constexpr const char * c_str () const; constexpr const char * data () const; std::string to_string() const; constexpr operator const char* () const; constexpr long long to_number () const; }; template<typename charT> class basic_string_literal<charT> { template <typename charU> friend constexpr basic_string_literal operator ""S<charU>(); private: static constexpr const charT _data[] = { '\0' }; constexpr basic_string_literal() = default; public: using value_type = charT; using size_type = std::size_t; using difference_type = std::size_t; using tail_type = basic_string_literal<charT>; constexpr size_type size() const; constexpr size_type length() const; constexpr bool empty() const; // These accessor methods always return the null character constexpr charT operator[] (size_t pos) const; constexpr charT at(size_t pos) const; constexpr charT back() const; constexpr charT front() const; template <charT... OtherChars> constexpr int compare(const basic_string_literal<charT, OtherChars...>& other) const; constexpr int compare(const basic_string<charT>& str) const; constexpr int compare(std::size_t pos1, std::size_t count1, const basic_string<charT>& str) const; constexpr int compare(std::size_t pos1, std::size_t count1, const basic_string<charT>& str, std::size_t pos2, std::size_t count2) const; constexpr int compare(const charT* s) const; constexpr int compare(std::size_t pos1, std::size_t count1, const charT* s) const; constexpr int compare(std::size_t pos1, std::size_t count1, const charT* s, std::size_t count2) const; constexpr const char * c_str() const; constexpr const char * data() const; std::string to_string() const; constexpr size_type to_number() const; constexpr operator const char* () const; operator std::string() const; }; template <typename charT, charT... Chars> constexpr basic_string_literal<charT, Chars...> operator""S() { return basic_string_literal<charT, Chars...>(); } // Concatenation template <typename charT, charT... LeftChars, charT... RightChars>; inline constexpr auto operator+ (const basic_string_literal<charT, LeftChars...>& l, const basic_string_literal<charT, RightChars...>& r) -> basic_string_literal<charT, LeftChars..., RightChars...>; // Relational operators template <typename charT, charT... OtherChars>; constexpr bool operator== (const basic_string_literal<charT, OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator!= (const basic_string_literal<charT, OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator< (const basic_string_literal<charT, >OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator<= (const basic_string_literal<charT, OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator> (const basic_string_literal<charT, OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator>= (const basic_string_literal<charT, OtherChars...>& lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator== (const charT* lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator== (const basic_string_literal<charT, OtherChars...>& lhs, const charT* rhs); template <typename charT, charT... OtherCharsbasic_string_literal<charT, OtherChars...>& constexpr bool operator!= (const charT* lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator!= (const basic_string_literal<charT, OtherChars...>& lhs, const charT* rhs); template <typename charT, charT... OtherChars>; constexpr bool operator< (const charT* lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator< (const basic_string_literal<charT, OtherChars...>& lhs, const charT* rhs); template <typename charT, charT... OtherChars>; constexpr bool operator<= (const charT* lhs, const basic_string_literal<charT, OtherChars...>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator<<= (const basic_string<charT,Traits,Alloc>& lhs, const charT* rhs); template <typename charT, charT... OtherChars>; constexpr bool operator> (const charT* lhs, const basic_string<charT,Traits,Alloc>& rhs); template <typename charT, charT... OtherChars>; constexpr bool operator> (const basic_string<charT,Traits,Alloc>& lhs, const charT* lhs); template <typename charT, charT... OtherChars>; constexpr bool operator>= (const charT* lhs, const basic_string<charT,Traits,Alloc>& rhs); template <typename CharT, class traits, class Alloc> constexpr bool operator>= (const basic_string<charT,Traits,Alloc>& lhs, const charT* rhs); // Stream insertion operator template <typename charT, charT... Chars> inline std::ostream& operator<< (std::ostream& os, const basic_string_literal<charT, Chars...>& str);
basic_string_literal
template
template <typename charT, charT... Chars> inline constexpr basic_string_literal<charT, Chars...> operator""S ();
I'd like to thank my employer, Perceptive Software, for their continued support of my work with the committee. Also many thanks to the brave souls on the SG7 mailing list who are contributing to our ongoing efforts towards compile-time reflection support in the langauge and library. Special thanks to Richard Smith who paved the way with N3599, particularly the implementation of that paper in clang, so that I could provide working examples for this paper.