読者です 読者をやめる 読者になる 読者になる

C++11 よく使いそうな機能

#include "stdafx.h"

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <chrono>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>

using namespace std;

class Someone
{
public :
        Someone()
        {
            cout << "コンストラクタ" << endl;
        }
        ~Someone()
        {
            cout << "デストラクタ" <<  endl;
        }

        void Update()
        {
            cout << "アップデート" << endl;
        }

};

static void func1()
{
    string message = "This is a pen";

    // 文字列messageを空白文字で区切ってvに格納
    vector<string> v;
    boost::algorithm::split(v, message, boost::algorithm::is_space());

    // vの要素を"-"で結合して表示
    cout << boost::algorithm::join(v, "-") << endl;

}

static void func2()
{
    string str1 = "this   is a   pen";

    // デフォルトでは、区切り文字(空白とかコンマとか)で分割する。
    typedef boost::tokenizer<> tokenizer1;
    tokenizer1 tok1(str1);

    for (tokenizer1::iterator it = tok1.begin(); it != tok1.end(); ++it)
        cout << "TOKEN: " << *it << endl;


    string str2 = "20020903";

    // 4文字、2文字、2文字に分割してみる。
    const int offsets[] = { 4, 2, 2 };
    boost::offset_separator ofs(offsets, offsets + 3);

    typedef boost::tokenizer<boost::offset_separator> tokenizer2;
    tokenizer2 tok2(str2, ofs);

    for (tokenizer2::iterator it = tok2.begin(); it != tok2.end(); ++it)
        cout << "TOKEN: " << *it << endl;


}

static void file_controle()
{
    namespace fs = boost::filesystem;

    // ディレクトリ作成
    fs::path dir("my_dir");
    fs::create_directory(dir);

    // ファイルを開いて書き込みー
    // ディレクトリ名とファイル名の結合は / 演算子で
    fs::ofstream f(dir / "test.txt");
    f << "Hello!" << endl;
    f.close();

    // カレントディレクトリのファイル一覧してみよう
    fs::directory_iterator end;
    for (fs::directory_iterator it(fs::current_path()); it != end; ++it)
    {
        if (fs::is_directory(*it))
            cout << "D ";
        else
            cout << "F ";
        // leaf() パス情報を切って、ファイルの名前部分のみ取り出し
        cout << it->path() << endl;
    }

}

class urger
{
    typedef boost::mutex::scoped_lock lock;
    volatile bool                     end_flag;
    boost::mutex                      ef_guard;
    boost::condition_variable_any     exitRequest;

public:
    urger() : end_flag(false) {}

    // スレッドのメインルーチン
    void u_main()
    {
        // 基本的に無限ループしておく
        for (;;)
        {
            lock lk(ef_guard);
            if (end_flag) break;

            // 現在の5秒後の時間を計算
            boost::xtime xt;
            boost::xtime_get(&xt, boost::TIME_UTC_);
            xt.sec += 5;

            // 終了通知を待ちます。ただし5秒たったら待ち解除
            if (exitRequest.timed_wait(lk, xt)) break;
            else cout << "\n何か書くのじゃー!: " << flush;
        }
    }

    void exit()
    {
        // 終了を通知します。
        lock lk(ef_guard);
        end_flag = true;
        exitRequest.notify_one();
    }
};

static void thread_test()
{
    // 催促スレッド起動
    urger u;
    boost::thread thr(&urger::u_main, &u);

    // 入力待ち
    cout << "何か書いてね: ";
    string str;
    getline(cin, str);


    // 入力が終わったら、終了して欲しいことをスレッドに通知
    u.exit();

    // 催促スレッドの終了待ち
    thr.join();

}

static void xml_read()
{
    //deleteのいらないポインタ
    shared_ptr<Someone> ptr(new Someone);
    shared_ptr<Someone> ptr2 = make_shared<Someone>();  //こっちのほうが早い

    const string xml_file_name = "./conf.xml";

    //xmlファイルが存在するかチェック
    const boost::filesystem::path xml_path = xml_file_name;
    boost::system::error_code error;
    const bool result = boost::filesystem::exists(xml_path, error);
    if (!result || error) {
        std::cout << xml_file_name << " ファイルがない" << std::endl;
        return;
    }



    //xmlファイルの読み込み
    boost::property_tree::ptree xml_root;
    read_xml(xml_file_name, xml_root);  

    //要素を単体で取得
    boost::optional<std::string> str = xml_root.get_optional<std::string>("conf.gmm_history");
    int param = boost::lexical_cast<int>(str.get());

    //子構造になっている要素を取得
    BOOST_FOREACH(const boost::property_tree::ptree::value_type& child, xml_root.get_child("conf.values")) {
        const int value = boost::lexical_cast<int>(child.second.data());
        std::cout << value << std::endl;
    }

    //属性を取得
    if (boost::optional<int> id = xml_root.get_optional<int>("conf.data.<xmlattr>.id")) {
        std::cout << id.get() << std::endl;
    }
    if (boost::optional<string> name = xml_root.get_optional<string>("conf.data.<xmlattr>.name")) {
        std::cout << name.get() << std::endl;
    }
}

static void func_random()
{
    mt19937 rand;

    //ランダム生成
    for (int i = 0; i < 10; i++)
    {
        cout << rand() << '\n';
    }

    //指定した範囲の整数で出力
    uniform_int_distribution<int> dist(1, 6);
    for (int i = 0; i < 10; i++)
    {
        cout << dist(rand) << '\n';
    }

    //指定した範囲の実数で出力
    uniform_real_distribution<double> dist_real(-100.0, 100.0);
    for (int i = 0; i < 10; i++)
    {
        cout << dist_real(rand) << '\n';
    }
}

static void func_auto()
{
    //型名 自動推論
    auto x = 5;
    auto y = 3.5f;
    auto z = sin(3.14);

}

static void func_loop_range()
{
    int scores[5] = { 10, 20, 30, 40, 50 };

    //配列の最初から最後までを出力
    for (const auto score : scores)
    {
        cout << score << '\n';
    }

    //begin()、end()関数があるのら使える
    vector<int> v = { 1, 2, 3 };
    list<double> li = { 5.0, 6.0, 7.0, };
    string str = "testtest";

    for (auto n:v) 
    {
        cout << n << endl;
    }
    for (auto x : li)
    {
        cout << x << endl;
    }
    for (auto ch : str)
    {
        cout << ch << endl;
    }

    Someone obj1, obj2;

    vector<Someone> some_vec;
    some_vec.push_back(obj1);
    some_vec.push_back(obj2);

    //コピーを避けるために参照
    for (auto& o : some_vec)
        o.Update();

}

static void func_ramda()
{
    vector<int> v = { 0, 1, 2, 3, 4, 5 };

    //coun_if の引数で関数ポインタを渡す必要がある
    //ラムダ式を使えば、新たに関数を作成しなくて良い。(コードから探す必要がない)
    size_t x = count_if(v.begin(),
                        v.end(),
                        [](int n){ return n % 2 == 0; }     //ラムダ式
                       );

    //ラムダ式はこの形
    //[]()->T{}

    auto Square = [](int n){return n*n; };
    cout << Square(9) << endl;
}

static void func_class_enum()
{
    enum class Team {RED,WHITE};    //整数型に変換されない

//  int a = RED;//これができない
}

static void func_array()
{
    //配列の新しい記述方法
    //size() at() begin() end() fill()などのメンバ関数を持っている
    array<int, 100> ar;

    for (int i = 0; i < ar.size(); i++)
    {
        ar[i] = i;
    }

    array<int, 5> a = { 1, 2, 3, 4, 5 };
    array<int, 5> b;

    b.fill(100);    //要素をすべて100にする。
    a = b;          //要素コピー
    a[0] = 0;
    for (auto n : a)
    {
        cout << n << endl;
    }
}

//便利な関数
static void func_some_algo()
{
    const int   a = 5, b = 10,c = 2;

    const int small = min({ a, b, c }); //最小値
    const int large = max({ a, b, c }); //最大値


    array<int, 100> arr;
    for (unsigned int i = 0; i < arr.size(); i++)
    {
        arr.at(i) = i;
    }

    //全要素の条件チェック
    const bool chk = all_of(arr.begin(), arr.end(), [](int n){return n <= 500; });  //すべての要素が条件を満たしていたらtrue

    //時間測定
    const auto start = chrono::system_clock::now();
    for (int i = 0; i < 100000;i++)
    {
        int a = 0;
        a++;
    }
    const auto end = chrono::system_clock::now();
    const chrono::duration<double> elapsed = end - start;
    cout << "経過時間 :" << elapsed.count() << "秒" << endl;

    //時間の足し算
    const chrono::minutes min(5);
    const chrono::seconds sec(15);
    const auto result = min + sec;

}


void main()
{
/*  func1();
    func2();
    file_controle();
    thread_test();
*/
    xml_read();
    func_random();
    func_loop_range();
    func_ramda();
    func_array();
    func_some_algo();

    //imgフォルダにある画像ファイルを探す
    namespace fs = boost::filesystem;
    fs::directory_iterator end;
    boost::filesystem::path fs_path = fs::current_path();
    fs_path += "\\img";

    //ファイル名の配列
    vector<boost::filesystem::path> file_name_vector;

    for (fs::directory_iterator it(fs_path); it != end; ++it)
    {
        //ファイルの名前を取得
        if (!fs::is_directory(*it))
        {
            cout << it->path() << endl;
            file_name_vector.push_back(it->path());
        }
    }
}