C++について、知っていそうで知らないこと、素朴な疑問など。(新着順)
enumで定義した変数は、暗黙のコンストラクタが呼ばれるとゼロが設定されます。 特定の値(たとえば、-1など)で初期化したい場合に便利なenumのwrapperクラスを作ってみました。
#include <iostream> #include <map> using namespace std; enum Hoges { Invalid = -1, Hoge = 0, Fuga = 1, Piyo = 2, Hogera = 3, PiyoPiyo = 4, }; // このmapは、値の初期値はHogeになる map <int, Hoges> hoges1; // 初期値をテンプレートパラメータで指定するenumクラス template <typename EnumType, EnumType InitialValue> struct initialized_enum { EnumType value_; initialized_enum(EnumType v = InitialValue) : value_(v) {} operator EnumType () const { return value_; } }; // このmapは、初期値がInvalid(-1)になる map <int, initialized_enum<Hoges, Invalid>> hoges2; int main() { // Hogesの初期値は、Invalidにしたいけど、Hogeになる cout << hoges1[0] << endl; // initialized_enumだと、初期値を入れてくれる cout << hoges2[0] << endl; }
http://melpon.org/wandbox/permlink/DSQ21IThska1JTQk
通常のクラス変数は、cppなどで明示的に宣言しないとインスタンスが生成されませんが、
テンプレートクラスの場合は、ヘッダファイルで宣言するだけでクラス変数のインスタンスが生成されます。
意外と知られていないですが、便利な機能です。
http://melpon.org/wandbox/permlink/kKGoK7YiFfmkJyyM
VisualStudioでは、ソースファイルの文字形式にかかわらず、コンパイル時に文字列リテラルはすべてシフトJISに変換されてしまいます。
たとえば、printf("漢字")というプログラムで、ソースコードがUTF-8でも実行時にはシフトJISで表示されます。
コンパイル時の文字コード変換機能をOFFにするやり方はわかりませんが、強制的にUTF-8にするには、以下の方法で可能です。
#if defined(_MSC_VER) // 文字リテラルをUTF-8として処理する #pragma execution_character_set("utf-8") #endif
XMLの文字エスケープのサンプル
#include <iostream> #include <string> #include <boost/regex.hpp> namespace { using std::string; using boost::regex; using boost::regex_replace; string escape(const string& src) { regex reg("(<)|(>)|(&)|(\\\")|(')"); string fmt("(?1<)(?2>)(?3&)(?4")(?5')"); return regex_replace(src, reg, fmt, boost::match_default|boost::format_all); } string unescape(const string& src) { regex reg("(<)|(>)|(&)|(")|(')"); string fmt("(?1<)(?2>)(?3&)(?4\\\")(?5')"); return regex_replace(src, reg, fmt, boost::match_default|boost::format_all); } } int main() { using namespace std; string src = "hoge<hoge> fuga<'fuga'> &>_<\" <o'o> < &\n"; string result = escape(src); cout << src << result << unescape(result); }
output
hoge<hoge> fuga<'fuga'> &>_<" <o'o> < & hoge<hoge> fuga<'fuga'> &>_<" <o'o> &lt; &amp; hoge<hoge> fuga<'fuga'> &>_<" <o'o> < &
便利で高速なemplaceですが、mapやunordered_mapのように、pair型として保持するコンテナの場合、emplaceするときに困った問題があります。
1つの値から生成できるkey, valueの場合は問題ないのですが、
map<int,int> hoge; hoge.emplace(1,2); // OK
生成に2つの値が必要なクラスを格納する場合、問題があります。
struct Point { Point(int x, int y); }; map<int, Point> hoge; hoge.emplace(1,2,3); // コンパイルエラー
この書式では、(1,2,3)から、pair<int(1), Point(2,3)> を推測してくれません。 こんな時は、"piecewise_construct"という呪文を使えば、pairを召喚できます。
#include <vector> #include <map> #include <iostream> struct Point { int x_; int y_; Point(int x,int y) : x_(x), y_(y) {} }; int main(int ac, char* av[]) { using namespace std; // vectorなら問題 ない// vector<Point> hoge; hoge.emplace_back(1,2); // mapの場合は、key,valueでOK! map<string, int> intMap; intMap.emplace("hoge", 1); // valueのコンストラクタの引数が2個以上の場合は厄介! map<string, Point> hogeMap; // hogeMap.emplace("hoge", 1, 2); // compile error! hogeMap.emplace(piecewise_construct // pairのコンストラクタを召喚する呪文! , forward_as_tuple("hoge") // tuple型の生成。make_tupleだとコピーされるので、 , forward_as_tuple(1,2)); // forward_as_tupleを使う }
参考URL
定数の定義をソースコード上で行う場合、定数の定義と値の定義を同時に行いたい場合があります。
通常はこのように書きます。
enum EnumHoge { hoge, fuga, piyo }; struct HogeHoge { EnumHoge id; float value; const char* name; } const table[] = { { hoge, 1.0f, "hoge" }, { fuga, 2.0f, "fuga" }, { piyo, 3.0f, "piyo" }, };
enumの定義と構造体の定義が冗長で、名前の文字列の定義も冗長です。
しかし、魂を悪魔(#define)に売り渡せば、一発で記述できます。
// ここで定数を定義する(冗長でない単一の記載で済ませる) #define LIST \ DEF(hoge, 1.0f), \ DEF(fuga, 2.0f), \ DEF(piyo, 3.0f) // enumの生成 #undef DEF #define DEF(a, b) a enum EnumHoge { LIST }; // 構造体の生成 #undef DEF #define DEF(a, b) {a, b, #a} struct HogeHoge { EnumHoge id; float value; const char* name; } const table[] = { LIST };
使用例
#include <stdio.h> int main(int ac, char*av []) { for (size_t n = 0; n < sizeof(table)/sizeof(HogeHoge); ++n) { printf("table[%d] = id:%d value:%f name='%s'\n", n, table[n].id, table[n].value, table[n].name); } }
結果
table[0] = id:0 value:1.000000 name='hoge' table[1] = id:1 value:2.000000 name='gufa' table[2] = id:2 value:3.000000 name='piyo'
ideone: http://ideone.com/HEIsAa#view_edit_box
// decltypeを使ってコンテナに要素を追加する // push_back()を持っている場合 template <typename CT, typename VT> inline auto push_to_container(CT& container, VT&& val, int=0) -> decltype(container.push_back(val)) { return container.push_back(val); } // push()がある場合 template <typename CT, typename VT> inline auto push_to_container(CT& container, VT&& val) -> decltype(container.push(val)) { return container.push(val); }
使用例
std::vector<int> hoge; std::priority_queue<int> fuga; ... push_to_container(hoge, 1); // hoge.push_back(1)が呼ばれる push_to_container(fuga, 1); // fuga.push(1)が呼ばれる
参考にしたページ
VC++では、イテレーターの範囲チェックが行われており、安全な反面、若干遅いです。
以下の定義を行うことで、範囲チェックを無効にできます。(C++ポケットリファレンスより引用)
#define _SECURE_SCL 0
ちなみに、以下の設定で範囲チェックが有効になります。
#define _SECURE_SCL_1 #define _HAS_ITERATOR_DEBUGGING 1
boost::mplのvectorやmapをfor_eachするサンプル。 mapのkeyだけ回すmap_keysのようなフィルタの例も作ってみました。
#include <iostream> #include <vector> #include <string> #include <typeinfo> #include <boost/mpl/list.hpp> #include <boost/mpl/map.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/key_type.hpp> using namespace boost; using namespace std; struct Disp { template <class Type> void operator()(const Type&) const { cout << typeid(Type).name() << endl; } template <typename K, typename V> void operator()(const mpl::pair<K,V>&) const { cout << typeid(K).name() << "," << typeid(V).name() << endl; } } disp; int main() { typedef mpl::list<int, std::string, char, std::vector<int> > tl; typedef mpl::map<mpl::pair<int,char>, mpl::pair<int,int>, mpl::pair<char, char> > t2; cout << "mpl list test" << endl; mpl::for_each<tl>(disp); cout << "mpl map test" << endl; mpl::for_each<t2>(disp); cout << "mpl map key_type test" << endl; mpl::for_each<t2, mpl::lambda<mpl::key_type<t2, mpl::_1> > >(disp); cout << "finish" << endl; return 0; }
cpp_akiraさんのページにあったサンプルにmapを足してみました。