【C++20】sリテラルについて

## std::string_literals::sリテラル

sリテラルについて調べたので記録を残す。



## sリテラルとは

文字列リテラルを受け取り、各文字型の`basic_string`を構築する機能を持つオペレーター(operator)のことである。



### basic_stringとは

`basic_string`クラスとは、あらゆる文字型を使用できるクラスである。



https://cpprefjp.github.io/reference/string/basic_string.html



## ヘッダ

ヘッダは下記のように`<string>`をインクルードする必要がある。

```c++
#include <string>
```



## 名前空間

名前空間の構造は以下のようになっている。

```c++
namespace std {
    inline namespace literals {
        inline namespace string_literals {
            ～～定義～～
        }
    }
}
```



### usingディレクティブ(using directive)

sリテラルを使用するには、下記のようにusingディレクティブを用いてnamespaceの検索範囲を拡張させる必要がある。

あるいは次項に記載するusing宣言でoperatorを指定のスコープに取り込む必要があります。

ちなみにinline namepsaceの部分は省略することができます。

```c++
using namespace std::literals::string_literals;
using namespace std::literals;
using namespace std::string_literals;
using namespace std;	// この書き方も可能だが、取り込まれる名前空間が膨大すぎるため推奨されない
```



https://cpprefjp.github.io/lang/cpp11/inline_namespaces.html



### using宣言

using宣言でoperatorだけをスコープに取り込みたい場合は下記のように記載する。

もちろんinline namepsaceの部分は省略することができます。

```c++
using std::literals::string_literals::operator""s;
using std::literals::operator""s;
using std::string_literals::operator""s;
using std::operator""s;	
```



## sリテラル実践

実際にsリテラルを使用してみる。

ついでにsリテラルを使用する場合と、使用しない場合を比較する。

プログラム内容：sリテラル使用時と不使用時、それぞれのサイズと中身、および型の比較を行う。



*source :  sliteral.cpp*

```c++
#include <iostream>
#include <string>
#include <typeinfo>
#include <cxxabi.h>

using std::literals::string_literals::operator""s; // enables s-suffix for std::string literals



char* demangle(const char *demangle) {
        int status;
        return abi::__cxa_demangle(demangle, 0, 0, &status);
}

int main()
{
        std::string s1 = "abc\0\0def";
        std::string s2 = "abc\0\0def"s;

        std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";
        std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";

        std::cout << std::endl;

        std::cout << demangle(typeid("abc\0\0def").name()) << std::endl;
        std::cout << demangle(typeid("abc\0\0def"s).name()) << std::endl;
}
```



*result*

```
$ g++ -std=c++20 -Wall -pedantic-errors -o program ./sliteral.cpp

$ ./program.exe
s1: 3 "abc"
s2: 8 "abcdef"

char [9]
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
```



https://cpprefjp.github.io/reference/typeinfo/type_info.html



http://0xcc.net/blog/archives/000095.html



## 実行結果まとめ

sリテラルを使用していない場合は、char型の配列で、null文字までを一塊とした文字列のようだ。これはC言語と変わらない。

一方でsリテラルを使用すると、basic_stringオブジェクトとなっている。



| sリテラル | ターゲット                           | size() | cout           |
| --------- | ------------------------------------ | ------ | -------------- |
| 不使用    | ```std::string s1 = "abc\0\0def"```  | 3      | ```"abc"```    |
| 使用      | ```std::string s2 = "abc\0\0def"s``` | 8      | ```"abcdef"``` |



| sリテラル | ターゲット          | 型                                                           |
| --------- | ------------------- | ------------------------------------------------------------ |
| 不使用    | ```"abc\0\0def"```  | ```char [9]```                                               |
| 使用      | ```"abc\0\0def"s``` | ```std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >``` |



## メモ

std::chrono_literals::sリテラル という算術リテラルもある。

つまり`10s` は10秒ですが、 `"10"s` は文字列となる。



https://cpprefjp.github.io/reference/chrono/duration/op_s.html



## 参考



https://cpprefjp.github.io/reference/string/basic_string/op_s.html



https://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s



https://runebook.dev/ja/docs/cpp/string/basic_string/operator_q__q_s



https://marycore.jp/prog/cpp/using-directive/