2015年5月31日日曜日

htop (cmd) OSX

htopコマンドはLinuxのプロセスおよびメモリ使用量のビューアである。macではtopコマンドのオプションがLinuxと異なるため、同様の情報をみたい場合に便利である。
導入も非常に簡単である。

# brew install htop [/usr/local/Cellar/tbb/4.3-20140724/include/tbb]
==> Downloading https://github.com/max-horvath/htop-osx/archive/0.8.2.2.tar.gz
######################################################################## 100.0%
==> ./autogen.sh
==> ./configure --prefix=/usr/local/Cellar/htop-osx/0.8.2.2
==> make install DEFAULT_INCLUDES='-iquote .'
==> Caveats
htop-osx requires root privileges to correctly display all running processes.
You can either run the program via `sudo` or set the setuid bit:
sudo chown root:wheel /usr/local/Cellar/htop-osx/0.8.2.2/bin/htop
sudo chmod u+s /usr/local/Cellar/htop-osx/0.8.2.2/bin/htop
You should be certain that you trust any software you grant root privileges.
==> Summary
🍺 /usr/local/Cellar/htop-osx/0.8.2.2: 11 files, 184K, built in 19 seconds
view raw htop_install.sh hosted with ❤ by GitHub
以下が実際に表示した様子である。Linuxのtopコマンドのオプション1よりも視認性が良い。


TBB OSX (C++)

OSXでTBBを利用したいときの最もお手軽な(だと思う)方法

# brew install tbb [/Library/Frameworks]
==> Downloading https://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb43_20140724oss_src.tgz
######################################################################## 100.0%
==> make tbb_build_prefix=BUILDPREFIX compiler=clang arch=intel64
/usr/local/Cellar/tbb/4.3-20140724: 104 files, 1.9M, built in 4.2 minutes

1 minute intro: Intel TBB parallel_for (C++)

TBB(Threading Building Blocks)は C++で並列化プログラムを簡単に記述するためのライブラリである。Intelが基本的な関数の使い方のビデオを公開している。以下はparallel_forのもの。機械学習のコードで大変よく登場する。


コードは以下である。
Threading Building Blocks
//
// tbb_intro.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/31.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <cmath>
#include <tbb/tbb.h>
double *output;
double *input;
int main(){
const int size = 20000000;
output = new double[size];
input = new double[size];
for(int i = 0; i < size; ++i){
input[i] = i;
}
tbb::parallel_for(0, size, 1, [=](int i){
output[i] = sqrt(sin(input[i]*sin(input[i]) + cos(input[i])*cos(input[i])));
}
);
return 0;
}

2015年5月30日土曜日

stringstream(C++)

stringstreamは、C++のストリームをstringに結びつける機能をもつクラスである。

stringstreamはstringに対して、<< や >>  演算子を提供する。
ostringstreamは出力のみ提供する。逆にistringstreamは入力のみを提供する。

//
// stringstream.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/30.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char* argv[]){
// stringstream
std::stringstream ss;
ss << "a";
ss << " ";
ss << 'b'; // 1文字であればcharを使うこと。strlenの最適化分のコンパイルが効率化できる。
std::cout << ss.str() << std::endl;
// ostringstream 書き出し
std::ostringstream oss;
// 様々な型をstringに流せる
oss << "test" << " " << 100;
std::cout << oss.str() << std::endl;
// istringstream 読み込み
std::istringstream iss(oss.str());
int n;
std::string s1;
std::string s2;
// 入力の順番で取得
iss >> s1 >> s2 >> n;
std::cout << s1 << std::endl;
std::cout << s2 << std::endl;
std::cout << n << std::endl;
}

2015年5月29日金曜日

numeric_limits(C++)

numeric_limitsは数値型の取りうる値の範囲についての情報を得るときに利用する。

以下のように使用する。

//
// limits.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <limits>
typedef long HashValueLong;
typedef unsigned long HashValueULong;
int main() {
// マクロ定義による取得
std::cout << "int max: " << INT_MAX << std::endl;
std::cout << "int min: " << INT_MIN << std::endl;
// クラステンプレートによる取得
std::cout << "int max: " << std::numeric_limits<int>::max() << std::endl; //2147483647
std::cout << "long max: " << std::numeric_limits<long>::max() << std::endl; //2147483647
std::cout << "long min: " << std::numeric_limits<long>::min() << std::endl;
std::cout << "long lowest: " << std::numeric_limits<long>::lowest() << std::endl;
std::cout << "double max: " << std::numeric_limits<double>::max() << std::endl;
std::cout << "double min: " << std::numeric_limits<double>::min() << std::endl;
std::cout << "double lowest: " << std::numeric_limits<double>::lowest() << std::endl;
// 型に依存しない書き方
std::cout << "HashValue(long): " << std::numeric_limits<HashValueLong>::max() << std::endl;
std::cout << "HashValue(unsigned long): " << std::numeric_limits<HashValueULong>::max() << std::endl;
return 0;
}
最小値を得たい場合に注意が必要である。
min()は必ずしも-max()を返すわけではなく、整数型と浮動小数点型とで意味が異なる。
C++11からはlowest()を利用すると良い。

minmax_element (C++)

minmax_elementはC++11から追加された機能であり、最小値/最大値を一括して求めるアルゴリズムの実装である。Boostのminmaxとはことなるので注意。

minmax_elementはvectorなどのコンテナを対象として最小値/最大値を求める。
戻り値の型はstd::pair型である。要素はポインタである。

minmaxもstd::pair型であるが、要素はminmaxのテンプレートのclass型である。

//
// minmax.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/29.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
int main(int argc, char* argv[]){
double x = 10.34, y = 3.5, z = 4.3;
// コンテナ
std::vector<double> v = {x, y, z};
auto minmax = std::minmax_element(v.begin(), v.end());
std::cout << "min: " << *minmax.first << std::endl;
std::cout << "max: " << *minmax.second << std::endl;
// 初期化子
auto t1 = std::minmax(1,999);
std::cout << "min: " << t1.first << std::endl;
std::cout << "max: " << t1.second << std::endl;
}
view raw minmax.cpp hosted with ❤ by GitHub

2015年5月28日木曜日

swap(C++)

swapは2つのオブジェクトの値を交換するときに使われるが、オブジェクトによって実装が異なるので動作に注意すること。

//
// swap.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/28.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char* argv[]){
// プリミティブ型
int a, b;
a = 10;
b = 20;
std::swap(a, b);
std::cout << a << std::endl;
std::cout << b << std::endl;
// array
int array_a1[4] = {10, 20, 30, 40}, array_b1[4] = {1,2,3,4};
std::swap(array_a1, array_b1);
for(auto i : array_a1){
std::cout << i << std::endl;
}
for(auto i : array_b1){
std::cout << i << std:: endl;
}
// array2
int array_a2[4] = {10, 20, 30, 40}, array_b2[4];
std::swap(array_a2, array_b2);
for(auto i : array_a2){
std::cout << i << std::endl; //初期化されていない
}
for(auto i : array_b2){
std::cout << i << std:: endl;
}
// array3
int array_a3[4] = {10, 20, 30, 40}, array_b3[5] = {1, 2, 3, 4, 5};
// std::swap(array_a3, array_b3); //NG 要素数の異なるarrayをswapできない
// vector
std::vector<std::string> v1;
std::vector<std::string> v2;
v1.emplace_back("abc");
v2.emplace_back("efg");
v2.emplace_back("hij");
// vectorは要素数がことなってもまるごと入れ替わる
v1.swap(v2);
for(auto i : v1){
std::cout << i << std::endl;
}
for(auto i : v2){
std::cout << i << std::endl;
}
// vector2
std::vector<std::string> v11;
std::vector<int> v22;
v11.emplace_back("abc");
v22.emplace_back(1);
v22.emplace_back(2);
// vectorは要素数がことなってもまるごと入れ替わる
// v11.swap(v22); //NG vectorは型が異なるとswapできない
}
view raw swap.cpp hosted with ❤ by GitHub

プリミティブ型の最大値を超えた場合のstatic_castの動作(C++)

プリミティブ型の最大値を超えている場合、static_cast はどのように動作するか。
//
// static_cast.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/28.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
int main(int argc, char* argv[]){
cout << static_cast<unsigned short>(-1) << endl;
cout << static_cast<unsigned short>(0) << endl;
cout << static_cast<unsigned short>(1) << endl;
cout << static_cast<unsigned short>(65535) << endl;
cout << static_cast<unsigned short>(65536) << endl;
cout << static_cast<unsigned short>(65537) << endl;
}
view raw short_cast.cpp hosted with ❤ by GitHub
出力は以下のようになる。
65535
0
1
65535
0
1

2015年5月25日月曜日

typeid (C++)

typeid演算子を利用して、型情報を取得できる。typeid演算子は、type_infoオブジェクト(type_infoクラスへの参照)を得る。

//
// typeinfo.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <typeinfo>
#include <string>
#include <cxxabi.h>
using namespace std;
template<typename T>
void func(T t){
cout << abi::__cxa_demangle(typeid(t).name(), 0, 0, 0) << endl;
}
int main(int argc, char* argv[]){
func<int>(12);
func<double>(12.0);
func<string>("abc");
}
view raw typeid.cpp hosted with ❤ by GitHub

emplace_back(C++11)

emplace_backはvectorの要素の追加を効率的に行えるようにC++11から追加された。

暗黙的型変換を利用して emplace_back により値をコンテナに格納するとコピーコンストラクタが呼ばれない。その分効率的に処理することが可能だ。ただし、暗黙的型変換を利用せず、自ら引数のオブジェクトのコンストラクタを呼び出すとコピーコンストラクタが呼ばれるので注意。
//
// emplacement.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
class A{
public:
A(int i){
cout << "constructor" << endl;
}
A(const A& a){
cout << "copy constructor" << endl;
}
~A(){
cout << "descructor" << endl;
}
};
int main(int argc, char* argv[]){
cout << "push_back ---" << endl;
vector<A> vec;
vec.push_back(0);
vec.clear();
cout << "emplace_back ---" <<endl;
vector<A> vec_e;
vec_e.emplace_back(0);
vec_e.clear();
cout << "emplace_back 非暗黙的変換 ---" <<endl;
vector<A> vec_en;
vec_en.emplace_back(A(0));
vec_en.clear();
cout << "emplace_back 事前確保 ---" <<endl;
// 事前確保
vector<A> vec_r;
vec_r.reserve(3);
vec_r.emplace_back(1);
vec_r.emplace_back(2);
vec_r.emplace_back(3);
vec_r.clear();
// vectorのvector
vector<vector<float>> vec_vec;
// vectorに3つの要素を初期値5でいれる
vec_vec.emplace_back(3, 5);
// vec_vecには1つのベクトルが入る
cout << vec_vec.size() << endl;
// vec_vec.backはvec_vec[0]と同じ
cout << vec_vec.back().size() << endl;
// ベクターには3つの要素
cout << vec_vec[0].size() << endl;
// 5で初期化
cout << vec_vec[0][0] << endl;
}
view raw emplacement.cpp hosted with ❤ by GitHub

CharTraits(C++)

CharTraitsはよくわかってない。標準出力などのbasic_streamを引数に受け取って流し込むようにtemplateに指定する使用方法を記載する。
//
// chartraits.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
struct result{
result(int num_success, int num_total){
num_success_ = num_success;
num_total_ = num_total;
}
double accuracy() const{
return (num_success_ * 100.0 / num_total_);
}
template<typename Char, typename CharTraits>
void print_summary(std::basic_ostream<Char, CharTraits>& os) const{
os << "accuracy: " << accuracy() << "% (" << num_success_ << "/" << num_total_ << ")" <<endl;
}
int num_success_;
int num_total_;
};
int main(int argc, char* argv[]){
result r(93, 100);
r.print_summary(std::cout);
}
view raw chartraits.cpp hosted with ❤ by GitHub

set(C++)

C++のsetは要素の数が有限の集合である。また、setの中の要素はソートされて保持されており、順序づけされたオブジェクトの集合とかんがえることができる。つまり、数学の集合とは意味が異なる。

setの良い点は、findによって目的のオブジェクトがsetに含まれているかどうかすぐに判別できる点であり、ソートされて保持された性質を利用して、ソート用途としてsetを使ってはならない。vectorをalgorithm sortでソートするよりもオーバーヘッドが高いからである。オーバーヘッドは、setが指定した要素をfindですぐに見つけられるように要素をinsertする際にインデックスすることからも想像に難くない。

また、ソートされることからわかるように、setの要素となる型にはオペレータ < が定義されている必要がある。これはmapのキーと同じである。

//
// set.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <set>
using namespace std;
int main(int argc, char* argv[]){
set<int> s;
// insert
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(5);
// setの要素数
cout << "set cnt is " << s.size() << endl;
// 保持している要素は、iteratorを受け取ることができる
set<int>::iterator i = s.find(3);
if(i == s.end()){
cout << "can not find." << endl;
}else{
cout << "find " << *i << endl;
}
// 保持していない要素は、iterator end()を受け取ることができる
set<int>:: iterator i_c = s.find(10);
if(i_c == s.end()){
cout << "can not find 10" << endl;
}else{
cout << *i << endl;
}
// 要素の削除
s.erase(3);
set<int>:: iterator i_e = s.find(3);
if(i_e == s.end()){
cout << "can not find 3" << endl;
}else{
cout << *i << endl;
}
// setの要素数
cout << "set cnt is " << s.size() << endl;
}
view raw set.cpp hosted with ❤ by GitHub

マニピュレータ iomanip (C++)

C++の入出力で書式を設定するのに マニピュレータ を使うと便利である。iosヘッダまたはiomanipヘッダに定義された機能を利用できる。

//
// iomanip.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char* argv[]){
// 8進数で表示
cout << oct << 10 << endl;
// 1度設定した値は引き継がれることに注意
cout << 10 << endl;
// 10進数表示に変更
cout << dec << 10 << endl;
// + をつける
cout << showpos << 10 << endl;
// -は通常どおりやればつく
cout << -10 << endl;
// フィールド幅を10桁に設定(上記では、マニピュレータに()がついていない。引数をとらない場合は()をつけない。なぜなら、オーバーロードされたオペレータ<<に渡されるのがマニピュレータのアドレスであるため。)
cout << setw(10) << 100 << endl;
// 16進数
cout << hex << 100 << endl;
// 基数をつける
cout << showbase << 100 << endl;
}
view raw iomanip.cpp hosted with ❤ by GitHub

stdexcept(C++)

stdexceptは標準的な例外クラスを提供する。

これらのクラス群に反映されているエラーモデルの種類
  • runtime error 実行時エラー
  • logic error 論理エラー
実行時エラーは、プログラムの制御の及ばない事象を起因とする。
論理エラーは、プログラムの内部的論理の誤りに起因する。

以下の様なクラスが定義されている。
  • exception
    • runtime error
      • range_error
      • overflow_error
      • underflow_error
    • logic error
      • domain_error
      • invalide_argument
      • length_error
      • out_of_range
これらのクラスは同じpublic関数が定義されており、ジェネリックな呼び出しが可能である。
explicit T(const string& what_arg){} 指定したメッセージをもつ例外オブジェクトの生成 
explicit T(const char* what_arg){} C++11 指定したメッセージをもつ例外オブジェクトの生成
virtual const char* what() const noexcept; メッセージの取得

//
// stdexcept.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/25.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <stdexcept>
using namespace std;
class processing{
public:
void function(){
throw std::logic_error("an logic error.");
}
};
int main(int argc, char* argv[]){
processing p;
try{
p.function();
}catch(const std::logic_error& e){
cout << e.what() <<endl;
}
}
view raw stdexcept.cpp hosted with ❤ by GitHub

2015年5月23日土曜日

enum(C++)

C++における列挙型enumは数種類のint型の値しかとることができない型を宣言する。
関数の引数や戻り値の値の意図を記述できる。

  • 値は明示しないと0から順に付けられる
  • サイズは環境依存であるため、通信プロトコルでの利用などでは注意すること

//
// enum.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/23.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
enum Gender{
MALE,
FEMALE
};
enum FunctionType{
NORMAL = 1,
ACTIVATION = 2,
LOSS = 3
};
enum Type{
YES = 1,
NO = -1
};
class A{
public:
Type function(){
return NO;
}
};
int main(int argc, char* argv[]){
A a;
cout << a.function() << endl;
}
view raw enum.cpp hosted with ❤ by GitHub

explicit(C++)

explicitは引数を1つだけとる変換コンストラクタが暗黙的に呼ばれることを防ぐ。

よくあるケース
  • explicitを記述しない変換コンストラクタをもつクラスは、= で初期化(コンストラクタ呼び出し)を記述できる
  • クラスの参照を引数に受け取る場合、意図せずして暗黙的に変換コンストラクタが呼び出されることがある
//
// explicit.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/23.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
class X {
public:
X(int x){}
};
class Y{
public:
Y(const X& x){}
};
class Str{
public:
Str(const char* str){str_ = str;}
~Str(){}
const char* toChar() const{
return str_;
};
private:
const char* str_;
};
class StrExplicit{
public:
explicit StrExplicit(const char* str){str_ = str;}
~StrExplicit(){}
const char* toChar() const{
return str_;
}
private:
const char* str_;
};
int main(int argc, char* argv[]){
// Yにintを指定しても、Xの変換コンストラクタが暗黙的に呼ばれ、X(3) を代入したことと同じになる
Y(3);
// 変換コンストラクタが暗黙的に呼ばれる(ただし、operator=とは異なる)
Str s = "abc";
cout << s.toChar() << endl;
//StrExplicit se = "efg"; // NG(暗黙的にコンストラクタを呼べないため、コンパイルエラー)
//cout << se.toChar() << endl;
StrExplicit se("efg");
cout << se.toChar() << endl;
}
view raw explicit.cpp hosted with ❤ by GitHub

2015年5月22日金曜日

関数宣言(C++)

関数の引数には型のみを指定することも可能
//
// function_argument.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
class A {
public:
int function(int a, int /*index*/){
return a;
}
};
int main(int argc, char* argv[]){
A* obj = new A();
cout << obj->function(10, 4) << endl;
}

overrideキーワード(C++11)

overrideキーワードは、意図せずして正しいオーバーライドになっていない状態を防ぐものである。

派生クラスの関数が、基底クラスの仮想関数をオーバーライドしていることを示す。

//
// override_keyword.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
struct A{
public:
virtual void function() = 0;
};
struct B : A{
public:
void function() override {
cout << "override" << endl;
}
};
int main(int argc, char* argv[]){
B obj;
obj.function();
}

transform(C++)

transformは変換を行うライブラリである。transformの処理内容は、関数オブジェクトやラムダ式を使って記述する。

//
// transform.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
// 関数オブジェクトで記述するため構造体
struct FunctionObject{
int operator()(int value){
return value * 2;
}
};
int main(int argc, char* argv[]){
vector<int> v(3);
fill(v.begin(), v.end(), 1);
for(int i : v){
cout << i << endl;
}
// 関数オブジェクトで変換を記述
transform(v.begin(), v.end(), v.begin(), FunctionObject());
for(int i : v){
cout << i << endl;
}
// ラムダ式で変換を記述 []の中は処理する値を参照で受け取るかどうかを記述する。空の場合は値渡し、&で参照渡しとなる。今回はプリミティブ型なので空でも処理はうまくいく。
transform(v.begin(), v.end(), v.begin(), [&](int x) { return x * 10; });
for(int i : v){
cout << i << endl;
}
// 別のベクトルに入れる場合
vector<int> v2(v.size());
transform(v.begin(), v.end(), v2.begin(), [&](int x) { return x * 100; });
for(int i : v2){
cout << i << endl;
}
}
view raw transform.cpp hosted with ❤ by GitHub

関数オブジェクト(C++)

()は関数呼び出しの演算子である。クラス定義中に、()をoperatorとしてオーバーロードすると、オブジェクトを関数呼び出しの形で呼び出せる。これが、関数オブジェクトである。
//
// function_object.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
// 10倍にして返す関数オブジェクト(このように定義すると、ヘッダーに処理内容も記述が可能)
class FunctionObject{
public:
int operator()(int value){
return value * 10;
}
};
struct FunctionStructObject{
int operator()(int value){
return value * 20;
}
};
int main(int argc, char* argv[]){
FunctionObject obj;
cout << obj(5) << endl;
FunctionStructObject structObj;
cout << structObj(5) << endl;
}

vector_array_for(C++)

配列、vectorforについて整理

配列中の要素を変更するには、参照を取得すること。

//
// vector_for.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[]){
vector<int> v(5);
fill(v.begin(), v.end(), 10);
// intのベクターをautoで取り出す
cout << "int auto" << endl;
for(auto a : v){
cout << a << endl;
}
// intのベクターをauto&で取り出しても同じ結果
cout << "int auto&" << endl;
for(auto& a : v){
cout << a << endl;
}
vector<string> v_str(5);
fill(v_str.begin(), v_str.end(), "abc");
// stringのベクターをautoで取り出しても読み出し可能だが、実体は変更できない
cout << "string auto" << endl;
for(auto b : v_str){
b = "change";
cout << b << endl;
}
cout << v_str[0] << endl;
// stringのベクターをauto&で取りだすと、配列内のstringの実体を変更できる
cout << "string auto&" << endl;
for(auto& b : v_str){
b = "change;";
cout << b << endl;
}
cout << v_str[0] << endl;
// vectorの配列ではどうか
vector<string> v_str1(2);
fill(v_str1.begin(), v_str1.end(), "abc1");
vector<string> v_str2(2);
fill(v_str2.begin(), v_str2.end(), "abc2");
vector<string> v_str3(2);
fill(v_str3.begin(), v_str3.end(), "abc3");
vector<string> v_array[3] = {v_str1, v_str2, v_str3};
// 配列からベクターをautoで取り出すと、&を付けないと実体が異なる
for(auto vs : v_array){
vs.resize(5);
cout << vs.size() << endl;
}
cout << v_array[0].size() << endl;
// 配列からベクターをauto&で取り出すと、配列内のvectorの実体を変更できる
for(auto& vs : v_array){
vs.resize(7);
cout << vs.size() << endl;
}
cout << v_array[0].size() << endl;
}

vector resize reserve(C++)

vectorresizereserveの動作についてまとめる。

//
// reserver_resize.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[]){
// デフォルトコンストラクタ
vector<int> vec_def;
cout << "vec_def size: " << vec_def.size() << ", capacity: " << vec_def.capacity() << endl;
// コンストラクタでサイズ指定
vector<int> vec_constructor(256);
cout << "vec_constructor size: " << vec_constructor.size() << ", capacity: " << vec_constructor.capacity() << endl;
// デフォルトコンストラクタで作成したvectorをreserveで変更
vec_def.reserve(128);
cout << "vec_def reserve size: " << vec_def.size() << ", capacity: " << vec_def.capacity() << endl;
// リサイズで変更
vec_def.resize(64);
cout << "vec_def resize size: " << vec_def.size() << ", capacity: " << vec_def.capacity() << endl;
// リサイズすると、size()も変更後と同じになる。出力すると、すべて0に初期化されていた。
for(auto& a : vec_def){
cout << a << " " ;
}
cout << endl;
// リサイズでは、初期化する値を決定することができる
vec_def.resize(128, 10);
cout << "vec_def resize size: " << vec_def.size() << ", capacity: " << vec_def.capacity() << endl;
for(auto& a : vec_def){
cout << a << " " ;
}
cout << endl;
}

fill(C++)

std::fillは配列やコンテナに対してレンジ指定してすべて同じ値を代入する関数である。

//
// fill.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v(10);
fill(v.begin(), v.end(), 3);
for(auto i : v){
cout << i << endl;
}
}
view raw fill.cpp hosted with ❤ by GitHub

vector iterator(C++)

C++のvectorのイテレータを扱う関数はtemplateで型に依存しないようにしておこう。
//
// iterator.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
template<typename Iter>
void func(Iter begin, Iter end){
// ++itでポインタを次へ進める
for (Iter it = begin; it != end; ++it){
// イテレータの要素へのアクセスはポインタの実体を指定
cout << *it << endl;
}
}
int main(){
// 配列の定義
vector<int> int_array;
// サンプルデータを入れる
int_array.push_back(2);
int_array.push_back(4);
int_array.push_back(6);
int_array.push_back(8);
// 要素の書き出し
func(int_array.begin(), int_array.end());
// 別の型の配列を定義
vector<double> double_array;
double_array.push_back(.3);
double_array.push_back(.4);
double_array.push_back(.5);
double_array.push_back(.6);
double_array.push_back(.7);
func(double_array.begin(), double_array.end());
}

nullptr(C++)

C++ではNULLは0でマクロ定義されており、プリミティブ型として扱われる。

nullptrはNULLをポインタ化したものであり、ポインタとして扱いたいときに利用する。

//
// nullptr.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
void func(void* p){
cout << "void*" << endl;
}
void func(int a){
cout << "int" << endl;
}
void func(nullptr_t p){
cout << "nullptr_t" << endl;
}
int main(){
func(12);
func(nullptr);
}
view raw nullptr.cpp hosted with ❤ by GitHub

コンストラクタ初期化子(C++)

以下のように使用するコンストラクタのコロンは、後ろにメンバ変数や親クラスを初期化する処理を記述することができる。

コンストラクタの中に処理を記述する場合と異なるのは、変数の初期化を省略できることである。

1億回の繰り返し処理で比較した結果、初期化子(コロンを使用した初期化処理)のほうが高速であった(どのくらい高速化は環境によって異なる)。

ただし、プリミティブ型については初期化の必要がないため、初期化子と代入で効率の違いはでないが、記述方法の一貫性やconst対策、コードの可読性のために初期化子を使用するべきである。

 親クラスの初期化についても以下のサンプルに記述しておく。
//
// constructor.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/22.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <chrono>
#include <string>
class constructor_init{
public:
constructor_init() : m_int(0), m_double(.1), m_str("abc"){}
private:
int m_int;
double m_double;
std::string m_str;
};
class constructor_noninit{
public:
constructor_noninit(){
m_int = 0;
m_double = 0;
m_str = "abc";
}
private:
int m_int;
double m_double;
std::string m_str;
};
class parent {
public:
parent(int a){
m_int = a;
}
public:
int m_int;
};
class child : public parent{
public:
child() : parent(2){
}
};
void init(bool constinit){
const auto startTime = std::chrono::system_clock::now();
for(unsigned int i = 0; i < 100000000; ++i){
if(constinit){
constructor_init* c = new constructor_init();
}else{
constructor_noninit* c = new constructor_noninit();
}
}
const auto endTime = std::chrono::system_clock::now();
const auto duration = endTime - startTime;
const auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
std::cout << "duration: " << msec << std::endl;
}
int main(){
// 親クラスの初期化
child* obj = new child();
std:: cout << obj->m_int << std::endl;
// コンストラクタ初期を使用した場合と代入の速度比較
init(true);
init(false);
}
view raw constructor.cpp hosted with ❤ by GitHub

2015年5月21日木曜日

alignment(C++11)

アラインメントとは、オブジェクトのための領域をメモリ上に確保する際のアドレスの境界位置のこと。
intのsizeが4バイトの環境では、intのデータを4の倍数のアドレスに配置すると、より高速にアクセスできる場合がある。

alignofの返すアライメント要求は、その型のオブジェクトをアドレス上に配置するためのものである。alignofが4の場合、該当のオブジェクトは4の倍数のアドレスに配置する必要がある。

アラインメントを指定するには、alignasを使う。変数及びメンバ変数のアラインメント属性を指定する。alignas(型名) は alignas(alignof(型名)) と同じである。

複数のアラインメントを指定すると、最も大きなアラインメントが選択される。

//
// alignment.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/21.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
// 構造体のすべてのメンバを4バイト単位で配置する例
struct S{
alignas(uint32_t) uint8_t a_;
alignas(uint32_t) uint16_t b_;
alignas(uint32_t) uint32_t c_;
};
int main(){
// int型のアライメント要求
cout << alignof(int) << endl;
cout << alignof(uint32_t) << endl;
}
view raw alignment.cpp hosted with ❤ by GitHub

size_t(C++)

size_t

長さ、大きさ、サイズ(メモリ量)を表現する型として用いるもので、sizeof演算子が返す符号なしの整数型(unsigned int)である。

//
// sizeof.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/21.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
using namespace std;
template<class ... T>
struct S{
static const size_t count = sizeof...(T);
};
int main(){
// int型で確保されるメモリサイズを出力
cout << sizeof 1 << endl;
int a = 2;
// sizeofに与えられた式は評価されないため、後に出力するaは2のまま
cout << sizeof ++a << endl;
cout << a << endl;
// 式でなく、型を与えても良い
cout << sizeof(int) << endl;
cout << sizeof(float) << endl;
cout << sizeof(double) << endl;
// 可変長引数の個数を取得する場合
S<int, char, double> t;
cout << t.count << endl;
}
view raw sizeof.cpp hosted with ❤ by GitHub

immintrin (C++)

immintrinはSIMD演算用の関数ヘッダーファイルである。

以下のようにすると、すべてのSIMD、AVX演算を利用することが可能である。
#include <immintrin.h>

SIMD -SIMDとは-

コンパイラ最適化入門 -明示的にベクトル化されたコードを記述する-

使いこなすの大変だなこれは。

Levenberg-Marquardt(レーベンバーグ・マーカート)

最適化(非線形最小化)手法の1つ。Deeplearning実装のために準備する。

非線形関数の最小値をみつける最適化を行うことが目的。
最も単純な方法は最急降下法であり、コスト関数を微分して小さくなる方向に進む。
最急降下法が大変遅いことを解決するのに、Gauss-Newton法(または単にニュートン法)を利用する。

Gauss-Newton法は、関数を2階微分して0になる箇所を探す。局所解に陥る危険はあるが高速に学習が進む。また、Gauss-Newton法が対象とする関数は2階微分を元の関数の1階微分の2乗で近似できる関数である。そのため、1階微分の2乗が0になる位置を探す。

上述の、Gauss-Newton法が局所解に陥る危険を減らしたものが、Levenberg-Marquardt法である。

コンピュータビジョン最先端ガイド3の岡谷先生によるバンドルアジャストメントの記述が丁寧である。

その他の最適化手法について、以下のスライドが詳しい。
- SGD、モーメンタム、etc・・・
http://www.slideshare.net/beam2d/deep-learningimplementation

unordered_map (C++11)

unordered_mapは連想配列(キーと値をセットで保持)を簡単に利用できるライブラリである。JavaではHashMapが使われる。

unordered_mapは名前のとおり、keyの順序に関係なくHashを使って格納する。
keyの順序によってソートしたい場合は、std::map を使えば良い。

mapへの操作は、unordered_map も std::map も基本的に同じである。

//
// unordered_map.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <unordered_map>
using namespace std;
int main(){
// keyとvalueの型を指定して初期化する
unordered_map<string, int> hash;
// key testの追加
hash["test"] = 10;
// key testのvalueを取得
cout << hash["test"] << endl;
// 存在しないkeyを指定しても、領域が確保される
cout << hash["test2"] << endl;
// at()では、存在するkey test が使える。
hash.at("test") = 20;
cout << hash.at("test") << endl;
// at()で、存在しないkey test2 を指定すると out_of_range例外が発生する
// hash.at("test2") = 30; NG
// keyとvalueをセットで追加したい場合、insertを使う
hash.insert(pair<string, int>("pair", 30));
cout << hash.at("pair") << endl;
// 状態を取得する
cout << hash.size() << endl;
cout << hash.empty() << endl;
// iterator
unordered_map<string, int>::iterator it = hash.begin();
while( it != hash.end() )
{
cout << (*it).first << ":" << (*it).second << endl;
++it;
}
return 0;
}
以下に他の機能も詳しく記載されている。

http://program.station.ez-net.jp/special/handbook/cpp/stl/map.asp

2015年5月20日水曜日

virtual function(C++)

virtual function(仮想関数)について

継承関係のあるクラスの関数をオーバーライドしたい場合にポリモーフィズム実現のために利用する 仮想関数 だが(実装を持たない場合、純粋仮想関数)、なぜ 仮想関数 を定義したクラスのデストラクタは virtualでなくてはならないのか。

 【復習】
仮想関数
//
// Stream.h
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#ifndef __CplusplusPractice__Stream__
#define __CplusplusPractice__Stream__
class Stream{
public:
double Get() const;
bool Set();
protected: //派生クラスで使用可能
virtual void SetBase() = 0;
double m_n;
};
#endif /* defined(__CplusplusPractice__Stream__) */
view raw Stream.hpp hosted with ❤ by GitHub
//
// Stream.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include "Stream.hpp"
using namespace std;
double Stream::Get() const{
return m_n;
}
bool Stream::Set(){
cout << "Stream::Set" << endl;
SetBase();
return m_n >= 0;
}
// 必ず子供で実装するので実装が不要→純粋仮想関数
//void Stream::SetBase(){
// cout << "Stream::SetBase" << endl;
// m_n = -1;
//}
view raw Stream.cpp hosted with ❤ by GitHub
//
// ArrayStream.h
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#ifndef __CplusplusPractice__ArrayStream__
#define __CplusplusPractice__ArrayStream__
#include "Stream.hpp"
class ArrayStream : public Stream{
public:
ArrayStream(const double* array); //コンストラクタ
protected:
virtual void SetBase();
private:
const double* m_array; //配列
int m_i; //現在のインデックス
};
#endif /* defined(__CplusplusPractice__ArrayStream__) */
view raw ArrayStream.hpp hosted with ❤ by GitHub
//
// ArrayStream.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include "ArrayStream.hpp"
using namespace std;
ArrayStream::ArrayStream(const double* array){
m_array = array;
m_i = 0;
}
void ArrayStream::SetBase(){
m_n = m_array[m_i];
++m_i;
}
view raw ArrayStream.cpp hosted with ❤ by GitHub
//
// InputStream.hpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#ifndef CplusplusPractice_InputStream_hpp
#define CplusplusPractice_InputStream_hpp
#include "Stream.hpp"
class InputStream : public Stream{
protected:
virtual void SetBase();
};
#endif
view raw InputStream.hpp hosted with ❤ by GitHub
//
// InputStream.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include "InputStream.hpp"
using namespace std;
void InputStream::SetBase(){
cin >> m_n;
}
view raw InputStream.cpp hosted with ❤ by GitHub
//
// inheritance.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include "Stream.hpp"
#include "InputStream.hpp"
#include "ArrayStream.hpp"
using namespace std;
bool Average(Stream& stream){
int count;
double avr = 0;
for(count = 0; stream.Set(); ++count){
avr += stream.Get();
}
if(count == 0){
return false;
}
avr /= count;
cout << "average is " << avr << endl;
count = 0;
return true;
}
int main(){
// ArrayStream
static const double array1[] = {1, 2, 3, 4, 5, 6, -1};
static const double array2[] = {2, 4, 5, 6, 1, -1};
static const double* const array[] = {array1, array2};
// sizeは全体のメモリサイズ / 要素(最初の一つ目)のメモリサイズ
static const int size = sizeof array / sizeof *array;
for(int i = 0; i < size; ++i){
ArrayStream stream(array[i]);
if(! Average(stream)){
//break;
}
}
// InputStream
while(true){
InputStream stream;
if(! Average(stream)){
break;
}
}
}

仮想関数テーブル
virtual function table, vtable という隠しメンバ変数を使って実現される。
ある仮想関数を呼び出したとき、実装にはどの関数かを管理するテーブル 
仮想関数テーブルは実行時、コンストラクタで初期化されてデストラクタで破棄されるので、不要な場合はvirtualにしないほうが仮想関数テーブルの分だけメモリ使用量は節約できるし、効率もあがる。

仮想関数を定義したクラスのデストラクタ
仮想関数の利用シーンは、「子クラスのポインタ」を「親クラスのポインタ」にキャストして使って、仮想関数の実装だけ入れ替えるようにして利用(ポリモーフィズム)がほとんどのはずである。

このとき、親クラスのポインタ(実体は子クラス)に対して delete した際、親クラスのデストラクタがvirtualでない場合、子クラスのデストラクタが呼ばれず、メモリリークが発生する。

また、親クラスが暗黙的に作成するデストラクタはvirutalでは無いので、内容がなかったとしても以下のように明示的に宣言すること。
virtual ~ParentClazz() {}

座標系スケール変換関数(template)

座標系のスケール変換を行う関数をテンプレート使って記述する。
//
// rescale.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
template<typename T, typename U>
U rescale(T x, T src_min, T src_max, U dst_min, U dst_max) {
U value = static_cast<U>(((x - src_min) * (dst_max - dst_min)) / (src_max - src_min) + dst_min);
return std::min(dst_max, std::max(value, dst_min));
}
int main(int argc, const char * argv[]) {
int a = 10;
int b = 1;
int c = 100;
int d = 300;
int e = 500;
int result = rescale(a, b, c, d, e);
std::cout << result << std::endl;
}
view raw scale.cpp hosted with ❤ by GitHub


macro

引数つきのmacroについて

以下のように、macroに引数を定義することが可能。うけとった引数の処理は続けて()に記述できる。

//
// macro.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/20.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#define CMACRO(x) (void)(x)
int main(int argc, const char * argv[]) {
std::cout << "con1.data = " << abi::__cxa_demangle(typeid(CMACRO(12)).name(), 0, 0, 0) << std::endl;
return 0;
}
view raw macro.cpp hosted with ❤ by GitHub

2015年5月19日火曜日

namespaceとoperator

namespaceとoperator
//
// namespace_operator.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
namespace namespace_op {
class Integer {
int value;
public:
int operator + (Integer obj) {
// biasの30が必ずプラスされるオペレータ+
return this->value + obj.value + 30;
}
Integer(int value) { this->value = value; }
};
}
using namespace namespace_op;
int main() {
Integer obj1(10) , obj2(100);
std::cout << obj1 + obj2 << std::endl;
return 0;
}

assert(C++)

assertでは、コードに開発者の意図を埋め込むことができる。

例えば、以下のコードはassertion failedとなる。

//
// assert.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <limits>
#include <cstdlib>
#include <assert.h>
typedef long long_type;
long base();
int main(int argc, const char * argv[]) {
long v = 32;
assert(v * base() > std::numeric_limits<long_type>::max());
return 0;
}
long base(){
return 200;
}
view raw assert.cpp hosted with ❤ by GitHub

static_cast (C++)

static_cast は 型変換(キャスト) の方法である

以下を満たす場合に使うことができる。

  • 暗黙的変換ができる
  • void * から他のポインターへの変換

汎用ポインタ(C++)

汎用ポインタ void* は、あらゆる型のポインタを代入できる。
void*型からのキャストはstatic_castが推奨される。

//
// genericpointer.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
// 構造体Container
struct Container{
void* data;
};
// 構造体Num
struct Num{
int n;
};
int main(int argc, const char * argv[]) {
const char* text = "text";
Container con1;
// Container構造体のdataにconst charのポインタを入れる(void*にキャストする)
con1.data = (void*)text;
std::cout << "con1.data = " << abi::__cxa_demangle(typeid(con1.data).name(), 0, 0, 0) << std::endl;
// Num構造体を動的確保
Num* numPointer = new Num();
numPointer->n = 42;
// Container構造体のdataにNum型のポインタを入れる
Container con2;
con2.data = (void*)numPointer;
std::cout << "con2.data = " << abi::__cxa_demangle(typeid(con1.data).name(), 0, 0, 0) << std::endl;
printf("%s\n", static_cast<const char*>(con1.data)); // 取り出す際にstatic_castする
printf("%d\n", ((Num*)con2.data)->n); //通常のキャストも可能
return 0;
}

cstdint(C++11)

cstdintには、bit数を指定できる整数が用意されている。


//
// cstdlib.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <cstdlib>
int main(int argc, const char * argv[]) {
std::cout << "HashValue(int8_t): " << std::numeric_limits<int8_t>::max() << std::endl;
std::cout << "HashValue(int16_t): " << std::numeric_limits<int16_t>::max() << std::endl;
std::cout << "HashValue(int32_t): " << std::numeric_limits<int32_t>::max() << std::endl;
std::cout << "HashValue(int64_t): " << std::numeric_limits<int64_t>::max() << std::endl;
std::cout << "HashValue(uint8_t): " << std::numeric_limits<uint8_t>::max() << std::endl;
std::cout << "HashValue(uint16_t): " << std::numeric_limits<uint16_t>::max() << std::endl;
std::cout << "HashValue(uint32_t): " << std::numeric_limits<uint32_t>::max() << std::endl;
std::cout << "HashValue(uint64_t): " << std::numeric_limits<uint64_t>::max() << std::endl;
return 0;
}
view raw cstdlib.cpp hosted with ❤ by GitHub

参考サイト
C++日本語リファレンス
http://cpprefjp.github.io/reference/cstdint.html

limits (C++)

プリミティブ型の最大値や最小値を取得する際、マクロ変数から取得することも可能だが、型安全な定数やメタ関数を利用して取得する。

 メタ関数は、こんな形式の関数

meta-function<type ...>::value()
typeに対してプリミティブ型でなく、typedefした型を入力すれば、型の変更に合わせてコードを書き換える必要なく値を取得できる。

//
// limits.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <limits>
typedef long HashValueLong;
typedef unsigned long HashValueULong;
int main(int argc, const char * argv[]) {
// マクロ定義による取得
std::cout << "int max: " << INT_MAX << std::endl;
std::cout << "int min: " << INT_MIN << std::endl;
// クラステンプレートによる取得
std::cout << "int max: " << std::numeric_limits<int>::max() << std::endl; //2147483647
std::cout << "long max: " << std::numeric_limits<long>::max() << std::endl; //2147483647
// 型に依存しない書き方
std::cout << "HashValue(long): " << std::numeric_limits<HashValueLong>::max() << std::endl;
std::cout << "HashValue(unsigned long): " << std::numeric_limits<HashValueULong>::max() << std::endl;
return 0;
}
view raw limits.cpp hosted with ❤ by GitHub

参考サイト
C++のプリミティブ型が取りうる最大値を取得する。
https://www.c3.club.kyutech.ac.jp/archives/1203

decltype と type traits (C++11)

decltype


decltype(expression) で式の型を得ることができる。

利用シーン


  • プロトタイプ宣言の型指定
  • 関数の戻り値の型を得る
typeinfoを併用して使い方を見てみる。typeinfoは実行時型情報(RTTI RunTimeTypeIdentification)を取得する機能である。

また、C++のコンパイラが名前マングルした(シンボルがuniqueな名前となるように)文字列を閲覧するのではなく、デマングルして宣言した型であることを確認する。

libstdc++cxxapi abi::__cxa_demangle()関数を利用する。

//
// decltype.cpp
// CplusplusPractice
//
// Created by masai on 2015/04/10.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <vector>
#include <typeinfo> //オブジェクトの型を知るためのライブラリ
#include <cxxabi.h>
using namespace std;
int methoz(int i);
double methoz(double d);
struct B {
virtual ~B(){}
};
struct D : B {
};
//戻り値型が引数aに合わせて変化させたい
//Bの子であるDの場合も存在する
auto test(const B& a) -> decltype(a) {
cout << "typeid(a)=" << abi::__cxa_demangle(typeid(a).name(), 0, 0, 0) << endl;
return a;
}
int main(int argc, const char * argv[]) {
// methoz(1)の戻り値の型をもつ変数nを定義する
decltype(methoz(1)) n = 3.4;
// int型として出力される
cout << n << endl;
decltype(methoz(2.3)) m = 3.4;
// double型として出力される
cout << m << endl;
// 型によって異なるvectorをつくる
auto a = 10;
vector<decltype(a)> vec;
// int型として挿入される
vec.push_back(3.3);
vec.push_back(10);
for(int i = 0; i < vec.size(); ++i){
cout << vec[i] << endl;
}
// 引数に合わせて戻り値が変化する関数
B b_instance;
D d_instance;
cout << abi::__cxa_demangle(typeid(test).name(), 0, 0, 0) << endl;
test(b_instance);
test(d_instance);
return 0;
}
view raw decltype.cpp hosted with ❤ by GitHub

type traits

型の特徴を調べたり、型の特徴を操作する関数
C++11では、type_traitsをインポートして enable_if が使える。
template <bool B, Class T = void>
struct enable_if;
enable_ifは、Bがtrueの時にtypedef T type;をもち、Bがfalseであればtypeをもたない。

SFINAE(Substitution Failure Is Not An Error)用途に使われる。
SFINAEは置き換え失敗はエラーにあらず、という意味で関数をオーバーライドする際、型変換がうまくいかなければオーバーライドの候補から自動ではずすことができる記述である。

ていうかいろんな書き方があってC++レベルが足りてない。以下の様な書き方があるってことを認識しておこう。

//
// typetraits.cpp
// CplusplusPractice
//
// Created by masai on 2015/05/19.
// Copyright (c) 2015年 masai. All rights reserved.
//
#include <iostream>
#include <type_traits>
// static_assertでコンパル時チェックを行うことが可能
// enable_ifにtrueのみ渡すと、デフォルトのvoidの型になる
static_assert(std::is_same<std::enable_if<true>::type, void>::value, "::type");
// enable_ifにtrueとintを渡すと、int型を返す
static_assert(std::is_same<std::enable_if<true, int>::type, int>::value, "::type");
// enable_ifにtrueとunsignedを渡すと、unsigned型を返す
static_assert(std::is_same<std::enable_if<true, unsigned>::type, unsigned>::value, "::type");
// enable_ifの第一引数にfalseを渡すと、type は無くなる
// **********************************************************************************
// is_integralはTがint型かどうかを確認する
// 以下の記述方法はTがintでない場合には、funcの呼び出しをエラーとする
template<typename T>
void func(T x, typename std::enable_if<std::is_integral<T>::value>::type* =0){
std::cout << "integral:" << x << std::endl;
}
// std::disable_if はないので、std::enable_if を使用する
template<typename T>
void func(T x, typename std::enable_if<!std::is_integral<T>::value>::type* =0){
std::cout << "other:" << x << std::endl;
}
// **********************************************************************************
// 以下は仮引数にenable_ifを記述しないタイプの書き方(enablerの利用)
// 条件無し。T は何型でもOKな関数f
template<class T>
void f(T const &){}
// T がint型と等しい時のみ有効な関数g
// is_integralはis_same<T, int>でも良い
extern void* enabler; // enabler
template<class T, typename std::enable_if<std::is_integral<T>::value>::type*& = enabler>
void g(T const &){
}
// **********************************************************************************
int main(int argc, const char * argv[]) {
// int型の変数a
int a = 0;
double d = 2.3;
// 構造体s
struct s{} b;
// func
func(a);
func(d);
f(a); // OK
f(b); // OK
g(a); // OK
//g(b); // gはint以外はエラーになる
return 0;
}
view raw typetraits.cpp hosted with ❤ by GitHub

2015年5月18日月曜日

3年計画の途中経過

以下の目標を実現できそうなところで仕事させてもらえそうなので、とても嬉しい。

  • 専門性(データマイニング・コンピュータビジョン)が活かせる、またはキャリア・スキルアップになる仕事をする。
  • 世界で仕事が出来る場所にいく

前のプロジェクトが死ぬレベルで忙しすぎてストップしてた英語を再開。
  • TOEIC 900点

DeepLearning 実装 準備編

DeepLearningの実装をスクラッチから行う。

まずは準備編として、3層多クラス分類のニューラルネットワークを実装した。

  • Androidアプリにも取り入れやすい
  • C++への書き換えも割と容易
ということでJavaで実装した。

動作確認用の可視化用クラスは、以下のものが使いやすかったので、多クラス分類用に修正して利用させていただいた。

NN法っていいよね-きしだのはてな

以下がコード。

ニューラルネットワーク


【課題】

  • 学習誤差を出力して、学習の進度を確認できるようにすること