Doc. No.: N4236
Date: 2014-10-10
Project: Programming Language C++, Reflection Study Group
Reply To: Michael Price
<michael.b.price.dev@gmail.com>

A compile-time string library template with UDL operator templates

I. Table of Contents

II. Introduction

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.

III. Motivation

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.

IV. Impact On the Standard

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.

V. Design Decisions

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.

VI. Technical Specification

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.

UDL operator template extension

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 types const C * and std::size_t, the The literal L is treated as a call of the form

  operator "" 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 is u8 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 have A 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 type char. 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.

Compile-time string template

Edit [string.classes] (21.3)/1 as follows:

The header <string> defines the basic_string class template for manipulating varying-length sequences of char-like objects and four typedefs, string, u16string, u32string, and wstring, that name the specializations basic_string<char>, basic_string<char16_t>, basic_string<char32_t>, and basic_string<wchar_t>, respectively. The header <string> also defines the basic_string_literal class template for manipulating compile-time sequences of char-like objects and four typedefs, string_literal, u16string_literal, u32string_literal, and wstring_literal, that name the specializations basic_string_literal<char>, basic_string_literal<char16_t>, basic_string_literal<char32_t>, and basic_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);
    

UDL operator template for basic_string_literal template

    
    template <typename charT, charT... Chars>
    inline constexpr basic_string_literal<charT, Chars...> operator""S ();
    
    

VII. Acknowledgements

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.

VIII. References

[1] Metaparse: Compile-time parsing with template metaprogramming
[2] https://github.com/michaelbprice/cxx_snippets/blob/master/string_literal/string_literal.cpp
[3] Literal operator templates for strings
[4] Compile-Time String: std::string_literal<n>