同じ文字列を表現する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++1714 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++1716 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++1725 cout << conv.to_bytes(ws) << endl;26 return 0;27}
汚いマクロを使ってる上に、グローバルが汚れています。もう少し上手くできないものなのでしょうか?どこかでこういうコード見たよ!などの情報だけでも結構です。よろしくお願いします。
注意点
リテラルでないといけません。実行時にstringからwstringにするのは簡単ですが、それなりにコストがかかります。今は例なのでこれだけですが、数はいくらでも増えるし、パフォーマンスを気にする部分と思ってください。

0 コメント