はかせのラボ

私の頭の中を書いていく雑記ブログです

C++ std::mapを試そうとしたらstd::wcoutに詰まった

あいさつ

どうも、はかせです。
今回はstd::mapとstd::wcoutの話です。

std::map

連想配列クラスといわれるものです。
C#のDictionaryに該当するものですね。
特定のkey値とそれに対応するvalue値を持つ配列です。

#include <map>
std::map<key,value> map;

keyとvalueにはそれぞれ型が入ります。

std::wcout

C++でワイド文字列(wchar_tとか)の標準出力ストリームです。
std::coutのワイド文字列版って認識で大丈夫だと思います。
入力版としてstd::wcinがあります。

なぜ触ったか

前回最後の方で意図したものと違う挙動が起きていました。
今私が考えている原因はキャッシュです。

文字も他のテクスチャと同様にキャッシュしているのですが、
フォント別で分けていないのでフォントが異なっていても
表示しようとしている文字が同じならば引っ掛かると思うんですよ。
なので既に別フォントで作った文字を引っ張ってきているのではないかという予想です。

という予想の元で動いていくと、
フォント別にキャッシュすれば解決するのではないかということで
フォント名をkeyとしてテクスチャデータの配列を作ろうということで
std::mapは触り始めました。

std::wcoutは私が普段使っているのがstd::wstringなので
そちらで動作検証したほうがいいだろうということで触りました。
(この浅はかな考えが私を沼へ誘うとは知らずに)

私がハマった沼

動作検証ということで
適当に値を設定したmapを用意して
コンソールから設定したkeyを入力し
対応したvalue一覧を表示するだけのプログラムです。

//フォント名でフォントテクスチャのパスを引きずり出すためのmap
std::map<std::wstring, std::vector<std::wstring>> mp;
//適当に設定したkeyを保持する配列
std::vector<std::wstring> keys;

#pragma region 適当に値を入れてみる
//ブログだと長すぎるのでカット
#pragma endregion

//入力を受けて対応するものがあれば表示なければ終了
while (true)
{
	//key値をコンソールから入力する
	std::wstring key;
	std::wcout << _T("key:");
	std::wcin >> key;
	std::wcout << std::endl;
	//入力されたkeyがkey値として登録されているか
	auto isKeyHit = false;
	for(auto k:keys)
	{
		if (key != k) continue;
		isKeyHit = true;
		//key値に対するvalue値を表示する
		for (auto v : mp[key])
		{
			std::wcout << v << std::endl;
		}
	}
	if (!isKeyHit) break;
}

値は日本語の50音をローマ字にしたものを格納しています。
(プログラム直書きで入れたのでローマ字の方が楽だった)
(例えばaと入力したらaiueoと出る感じ)

そして長い値直書きを終えて意気揚々と入力したらこれですよ。
f:id:hakase0274:20190306234616p:plain

値が表示されない・・・?

理由

基本的にはwcoutで素直にでるそうなのですが、
環境や設定によってはwcoutが
サポートされていないというか
機能していないというか
まぁそんな感じのことがあるそうです。
(標準出力だから環境依存なのも頷けるといえば頷ける)

では私の環境では絶対wcoutが使えないかというと
そういうわけではないらしく、
(素直にcout使えばよかったと今更ながら思った)
とあるおまじないをつけることで機能するそうです。
そのおまじないがこちら

std::wcout.imbue(std::locale(""));

これはロケールの設定を行う関数らしいです。
ロケールっていうのは表示する言語の設定をするものです。
一応日本製のものならデフォルト日本語で何もせずでるらしいですが、
私は出なかったのでこのおまじないを書きました。
さて、おまじないの効果はあったのでしょうか
f:id:hakase0274:20190306233412p:plain

無事表示されましたね。
内容も意図したとおりだったのでmapも無事使えてるみたいです。

あとがき

今回はstd::mapとstd::wcoutの話でした。
正直普通の文字列とワイド文字列を区別したりとか
ポインタだと先頭1文字しかとれないとか
文字を扱うだけなのに色々ありすぎなんですよね。
(まぁ使うメモリ量や文字コードに影響する部分だから仕方ないのかもしれませんが)

なんかどっかのタイミングで楽に文字が使えるようなラッパークラスとか作ってみたいですね。

それでは今回はこの辺でノシ