[解決済み] C++でコンパイル時の文字列を簡便に宣言する方法
質問
C++でコンパイル時に文字列を作成し操作できることは、いくつかの有用な用途があります。C++でコンパイル時に文字列を作成することは可能ですが、その処理は非常に面倒で、文字列を例えば文字の変種列として宣言する必要があるからです。
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
文字列の連結や部分文字列の抽出などの操作は、文字の並びに対する操作として簡単に実装することができます。 コンパイル時の文字列をもっと便利に宣言することはできないのでしょうか?もしそうでなければ、コンパイル時の文字列を便利に宣言できるような提案はありますか?
既存のアプローチが失敗する理由
理想的には、以下のようにコンパイル時の文字列を宣言できるようにしたいものです。
// Approach 1
using str1 = sequence<"Hello, world!">;
または、ユーザー定義のリテラルを使用します。
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
ここで
decltype(str2)
を持つことになります。
constexpr
コンストラクタを使用します。ということを利用して、アプローチ1のもっと雑なバージョンも実装可能です。
template <unsigned Size, const char Array[Size]>
struct foo;
ただし、配列には外部リンクが必要なので、アプローチ1を実現するためには、次のような書き方をしなければなりません。
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
言うまでもなく、これは非常に不便なことです。アプローチ2は、実は実装が不可能なのです。仮に、(
constexpr
) リテラル演算子の戻り値の型はどのように指定するのでしょうか?演算子は文字の可変長配列を返す必要があるので、そのためには
const char*
パラメータで戻り値の型を指定します。
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
この結果、コンパイルエラーになります。
s
は
constexpr
. 以下のようにして回避しようとしても、あまり役に立ちません。
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
規格では、この特定のリテラル演算子の形式は、整数型と浮動小数点型に予約されていることになっています。一方
123_s
を使えばうまくいくでしょう。
abc_s
はできません。ユーザー定義リテラルを完全に捨て、通常の
constexpr
という関数があります。
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
先ほどと同じように、配列のパラメータを
constexpr
関数は、それ自体がもはや
constexpr
の型になります。
文字列と文字列のサイズを引数にとり、文字列中の文字からなるシーケンスを返すCプリプロセッサマクロを定義することができるはずです(using..............................)。
BOOST_PP_FOR
文字列化、配列の添え字など)。しかし、私にはそのようなマクロを実装する時間(あるいは十分な興味)がありません =)。
どのように解決するのですか?
のエレガンスに匹敵するものを見たことがない。
Scott Schurrの
str_const
で発表しました。
C++ Now 2012
. これには
constexpr
とはいえ
その使い方と、できることを紹介します。
int
main()
{
constexpr str_const my_string = "Hello, world!";
static_assert(my_string.size() == 13, "");
static_assert(my_string[4] == 'o', "");
constexpr str_const my_other_string = my_string;
static_assert(my_string == my_other_string, "");
constexpr str_const world(my_string, 7, 5);
static_assert(world == "world", "");
// constexpr char x = world[5]; // Does not compile because index is out of range!
}
コンパイル時の範囲チェックほどクールなものはないでしょう!
使い方も、実装も、マクロを使わない。 また、文字列のサイズに人為的な制限もない。 実装をここに掲載したいところだが、Scottの暗黙の著作権を尊重する。 実装は、上でリンクした彼のプレゼンテーションの1枚のスライドにある。
C++17のアップデート
この回答を投稿してからの数年間で
std::string_view
は、私たちの道具箱の一部となりました。 以下は、上記を以下のように書き換えたものです。
string_view
:
#include <string_view>
int
main()
{
constexpr std::string_view my_string = "Hello, world!";
static_assert(my_string.size() == 13);
static_assert(my_string[4] == 'o');
constexpr std::string_view my_other_string = my_string;
static_assert(my_string == my_other_string);
constexpr std::string_view world(my_string.substr(7, 5));
static_assert(world == "world");
// constexpr char x = world.at(5); // Does not compile because index is out of range!
}
関連
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】抽象クラス型の無効なnew-expression
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み] JavaScriptで複数行の文字列を作成する
-
[解決済み] C#で文字列のエンコーディングを手動で指定せずに、一貫性のあるバイト表現を得るには?
-
[解決済み] ランダムな文字列を使用するこのコードは、なぜ "hello world" と表示されるのですか?
-
[解決済み] と'is'のどちらかを使って文字列を比較すると、異なる結果になることがあるのはなぜですか?
-
[解決済み] Bashで文字列を比較する方法
-
[解決済み] goで文字列の連結を効率的に行う方法
-
[解決済み] 文字列の一覧から空の文字列を削除する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++エラー:の初期化に一致するコンストラクタがありません。
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み】一致する関数ポインターを呼び出すためにタプルを「解凍」する