質問
同じ文字列を表現するchar/wchat_tの文字列リテラルをテンプレートを使って綺麗に共通化したい(正規化ではないです)。
前提
- プラットフォーム/処理系はできるだけ問わない
- C++11以降、もしくはC++14以降で動作すること(C++17以降の固有機能は使用しない)
背景
以下の例を参照
例
マルチバイト文字列(std::string)とワイド文字列(std::wstring)をそれぞれ日本語の括弧「」で括って表示するプログラムです。
C++
1#include <iostream> 2#include <locale> 3#include <string> 4#include <codecvt> 5using namespace std; 6string japanese_quote(const string& s) {return "「" + s + "」";} 7wstring japanese_quote(const wstring& s) {return L"「" + s + L"」";} 8int main() { 9 setlocale(LC_ALL, ""); 10 string mbs = japanese_quote(string("ほげ")); 11 wstring ws = japanese_quote(wstring(L"ほげ")); 12 cout << mbs << endl; 13 wstring_convert<codecvt_utf8<wchar_t>, wchar_t> conv; // deprecated by c++17 14 cout << conv.to_bytes(ws) << endl; 15 return 0; 16} 17// 出力: 18// 「ほげ」 19// 「ほげ」
ココでオーバーロードされているjapanese_quoteをテンプレートで共通化したいのですが、文字列リテラルをどうやって切り替えるかに悩んでいます。例えば、以下はエラーになります。
C++
1#include <iostream> 2#include <locale> 3#include <string> 4#include <codecvt> 5using namespace std; 6template<typename Char> 7basic_string<Char> japanese_quote(const basic_string<Char>& s) { 8 return "「" + s + "」"; 9} 10int main() { 11 setlocale(LC_ALL, ""); 12 string mbs = japanese_quote(string("ほげ")); 13 wstring ws = japanese_quote(wstring(L"ほげ")); 14 cout << mbs << endl; 15 wstring_convert<codecvt_utf8<wchar_t>, wchar_t> conv; // deprecated by c++17 16 cout << conv.to_bytes(ws) << endl; 17 return 0; 18}
std::wstringのとき、つまりCharがwchar_tのときに"「"や"」"などのリテラルをstd::wstringにできないからです(ワイド文字列リテラルでないため)。ワイド文字列リテラルにするにはL"「"やL"」"などとしないといけません。これをうまく実装する方法を尋ねるべく質問した次第です。
試したこと
背景の例でですが、今のところ何とか実装はできています。しかし綺麗とは言い難いし、まだ何とかなるような気がするので、お知恵をお借りしてもう少し綺麗にしたいのです。現状のコードは以下のとおりです。
C++
1#include <iostream> 2#include <locale> 3#include <string> 4#include <codecvt> 5using namespace std; 6#define LITERAL_CLASS(NAME, VALUE) \ 7template<typename T> \ 8struct NAME { \ 9 static const T* value(); \ 10}; \ 11template<> const char* NAME<char>::value() {return VALUE;} \ 12template<> const wchar_t* NAME<wchar_t>::value() {return L##VALUE;} 13LITERAL_CLASS(jp_bra, "「") 14LITERAL_CLASS(jp_ket, "」") 15template<typename Char> 16basic_string<Char> japanese_quote_tmpl(const basic_string<Char>& s) { 17 return jp_bra<Char>::value() + s + jp_ket<Char>::value(); 18} 19int main() { 20 setlocale(LC_ALL, ""); 21 string mbs = japanese_quote_tmpl(string("ほげ")); 22 wstring ws = japanese_quote_tmpl(wstring(L"ほげ")); 23 cout << mbs << endl; 24 wstring_convert<codecvt_utf8<wchar_t>, wchar_t> conv; // deprecated by c++17 25 cout << conv.to_bytes(ws) << endl; 26 return 0; 27}
汚いマクロを使ってる上に、グローバルが汚れています。もう少し上手くできないものなのでしょうか?どこかでこういうコード見たよ!などの情報だけでも結構です。よろしくお願いします。
注意点
リテラルでないといけません。実行時にstringからwstringにするのは簡単ですが、それなりにコストがかかります。今は例なのでこれだけですが、数はいくらでも増えるし、パフォーマンスを気にする部分と思ってください。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2023/03/30 16:33