デジタルちんぶろぐ

デジタルな話題

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  268  : 記事  0  : コメント  4382  : トラックバック  79

ニュース


技術以外は
ちんぶろぐ

記事カテゴリ

書庫

日記カテゴリ

8月に横浜で行われたC++ Dayでさらっと流されたCRTP。

普通ならコンパイルタイムポリモーフィズムとかで使われるんだろうけど、別の使い道ないかな?と思ってやってみたのがCSVの任意項目ピックアップ。

コメントもない汚いソースだけど、折角やってみたので。

 

今後使うかもしれないクラスだからこっちは標準ライブラリ以外使用しない

csvreader.h

#include 
#include 

#define SIZE_OF_ARRAY(ar)   (sizeof(ar) / sizeof(ar[0]))

#define MAKE_SETTER(prop)   set_##prop
#define MAKE_GETTER(prop)   get_##prop
#define MAKE_VALUE(prop)    prop##_value

#define MAKE_PROPERTY(prop)                                                         \
private:                                                                            \
    std::string MAKE_VALUE(prop);                                                   \
public:                                                                             \
    const std::string& MAKE_GETTER(prop)() const { return MAKE_VALUE(prop); }       \
    void MAKE_SETTER(prop)(const std::string& value) { MAKE_VALUE(prop) = value; }
#define MAKE_CALLER_ELEMENT(type, prop)                                             \
    property_manager::caller_map_element(#prop ,                              \
        property_manager::property_methods(&type::MAKE_SETTER(prop),          \
                                                &type::MAKE_GETTER(prop))),
#define CALLER_LIST(type)   property_manager::caller_list
#define DECLARE_CALLER_MAP(type) template<>                                         \
    property_manager::caller_map_type property_manager::caller_map(     \
        CALLER_LIST(type), &CALLER_LIST(type)[SIZE_OF_ARRAY(CALLER_LIST(type))]);
#define BEGIN_DECLARE_CALLER(type) template<>                                       \
    const property_manager::caller_map_element    CALLER_LIST(type)[] = {
#define END_DECLARE_CALLER(type) }; DECLARE_CALLER_MAP(type)
#define DECLARE_MANAGER_TYPE(type)  typedef property_manager  manager_type;
#define DECLARE_STRING_METHOD_BASE(type)                                            \
public:                                                                             \
    DECLARE_MANAGER_TYPE(type)                                                      \
    virtual const std::string& get_by_string(const std::string& key) const {        \
        return  manager_type::get_by_string(key);                                   \
    }                                                                               \
    virtual bool set_by_string(const std::string& key, const std::string& value) {  \
        return  manager_type::set_by_string(key, value) ? true : false;             \
    }

#define DECLARE_STRING_METHOD(type, super)                                          \
public:                                                                             \
    DECLARE_MANAGER_TYPE(type)                                                      \
    virtual const std::string& get_by_string(const std::string& key) const {        \
        const std::string&  value = manager_type::get_by_string(key);               \
        return  value.empty() ? super::get_by_string(key) : value;                  \
    }                                                                               \
    virtual bool set_by_string(const std::string& key, const std::string& value) {  \
        return  manager_type::set_by_string(key, value) ? true                      \
            : super::set_by_string(key, value);                                     \
    }

/**
 * プロパティを管理
 */
struct null_holder { const static std::string   null_str; };

template struct property_manager : public null_holder {
    typedef void    (T::*setter)(const std::string& value);
    typedef const std::string&  (T::*getter)() const;

    struct property_methods {
        setter  set;
        getter  get;
        property_methods(setter s, getter g) : set(s), get(g) {}
    };

    typedef std::map     caller_map_type;
    typedef typename caller_map_type::value_type        caller_map_element;
    typedef typename caller_map_type::iterator          caller_map_iterator;

private:
    const static    caller_map_element  caller_list[];
    static          caller_map_type     caller_map;

public:
    bool    set_by_string(const std::string& key, const std::string& value) {
        caller_map_iterator it = caller_map.find(key);
        if(it == caller_map.end()) {
            return  false;
        }

        (static_cast(this)->*it->second.set)(value);
        return  true;
    }

    const std::string&  get_by_string(const std::string& key) const {
        caller_map_iterator it = caller_map.find(key);
        if(it == caller_map.end()) {
            return  null_str;
        }

        return  (static_cast(this)->*it->second.get)();
    }
};

疲れたからこっちはboost使う

csvreader.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "csvreader.h"

const std::string   null_holder::null_str = std::string();

// ベースクラス
class base : public property_manager {
    MAKE_PROPERTY(Name)
    MAKE_PROPERTY(Kind)
    MAKE_PROPERTY(Price)
public:
    DECLARE_STRING_METHOD_BASE(base)
};

// 食べ物
class food : public base, public property_manager {
    MAKE_PROPERTY(Weight)

    DECLARE_STRING_METHOD(food, base)
};

// お酒
class liquor : public food, public property_manager {
    MAKE_PROPERTY(Number)
    MAKE_PROPERTY(Proof)

    DECLARE_STRING_METHOD(liquor, food)
};

// たばこ
class cigarette : public base, public property_manager {
    MAKE_PROPERTY(Number)
    MAKE_PROPERTY(Nicotine)

    DECLARE_STRING_METHOD(cigarette, base)
};

// ベースクラス用呼び出し定義
BEGIN_DECLARE_CALLER(base)
    MAKE_CALLER_ELEMENT(base, Name)
    MAKE_CALLER_ELEMENT(base, Kind)
    MAKE_CALLER_ELEMENT(base, Price)
END_DECLARE_CALLER(base)

// 食べ物用呼び出し定義
BEGIN_DECLARE_CALLER(food)
    MAKE_CALLER_ELEMENT(food, Weight)
END_DECLARE_CALLER(food)

// お酒用呼び出し定義
BEGIN_DECLARE_CALLER(liquor)
    MAKE_CALLER_ELEMENT(liquor, Number)
    MAKE_CALLER_ELEMENT(liquor, Proof)
END_DECLARE_CALLER(liquor)

// たばこ用呼び出し定義
BEGIN_DECLARE_CALLER(cigarette)
    MAKE_CALLER_ELEMENT(cigarette, Number)
    MAKE_CALLER_ELEMENT(cigarette, Nicotine)
END_DECLARE_CALLER(cigarette)

typedef boost::shared_ptr                         object_holder;
typedef std::vector                      object_array;
typedef std::vector                        string_array;
typedef boost::char_separator                     cvs_separator;
typedef boost::tokenizer >  cvs_tokenizer;
typedef std::pair             string_pair;

inline string_array get_cvs_tokens(const std::string& str)
{
    cvs_separator separator(",", 0, boost::keep_empty_tokens);
    cvs_tokenizer tokens(str, separator);
    return  string_array(tokens.begin(), tokens.end());
}


int main(int argc, const char* argv[])
{
    if(argc < 2) return 0;

    std::ifstream   ifs(argv[1]);
    if(!ifs.is_open()) return   0;
    std::string line;
    getline(ifs, line);
    string_array    tags = get_cvs_tokens(line);

    object_array            objs;
    boost::shared_ptr tmp;
    while(!getline(ifs, line).eof()) {
        tmp.reset(new base());
        string_array    params = get_cvs_tokens(line);
        string_array::iterator  itt = tags.begin();
        for(string_array::iterator it = params.begin(); it != params.end(); ++it, ++itt) {
            tmp->set_by_string(*itt, *it);
        }

        std::string kind = tmp->get_Kind();
        if(kind == "Food")              tmp.reset(new food());
        else if(kind == "Liquor")       tmp.reset(new liquor());
        else if(kind == "Cigarette")    tmp.reset(new cigarette());

        itt = tags.begin();
        for(string_array::iterator it = params.begin(); it != params.end(); ++it, ++itt) {
            tmp->set_by_string(*itt, *it);
        }

        objs.push_back(tmp);
    }

    for(object_array::iterator it = objs.begin(); it != objs.end(); ++it) {
        for(string_array::iterator itt = tags.begin(); itt != tags.end(); ++itt) {
            std::string value = (*it)->get_by_string(*itt);
            if(value.empty()) continue;
            std::cout << *itt << std::ends << ":" << value << std::endl;
        }
        std::cout << std::endl;
    }

    return  0;
}

このプログラムに以下のCSVを食わせる

Name Kind Price Weight Number Proof Nicotine Comment
Food 1000 100 1     お魚
牛肉 Food 2000 300 2     お肉
Cigarette 1500 0 5   0.9 高級煙草
氷結果汁 Liquor 380 350 1 11   世界一美味い
パチンコ Gamble priceless 1 4 1 1  

 

実行結果

Name :鯛
Kind :Food
Price :1000
Weight :100

Name :牛肉
Kind :Food
Price :2000
Weight :300

Name :峰
Kind :Cigarette
Price :1500
Number :5
Nicotine :0.9

Name :氷結果汁
Kind :Liquor
Price :380
Weight :350
Number :1
Proof :11

Name :パチンコ
Kind :Gamble
Price :priceless

 

各クラスがサポートしているパラメータのみが出力されている。

よしよし。

 

ヘルパーマクロの書式はMFCへのオマージュw

投稿日時 : 2008年11月19日 1:19

コメント

# re: セッションのアフターフォロー 2008/11/19 1:39 アキラ
cvsになってるのは仕様ですかw

# re: セッションのアフターフォロー 2008/11/19 1:46 あんどちん
> cvsになってるのは仕様ですかw
あ゛…
もう、直す気力ないからこのままw
# でもさぁ良く間違えるんだよねcsv/cvs。
# 実はこのソースも最初cvsreaderだったしw

# re: セッションのアフターフォロー 2008/11/19 1:52 アキラ
ぼくもよく間違うのでCSV関連のソースではつい目が行っちゃうというw

# re: セッションのアフターフォロー 2008/11/19 23:16 あんどちん
ってゆーかツッこまれるのってそういうとこだけなのよねぇw

# gBeGVIiAzajkM 2011/09/29 12:15 http://oemfinder.com
pQzhIg Heartfelt thanks..!

# XzOkhuuNBdpBP 2011/10/06 1:23 http://www.cpc-software.com/products/Download-Appl
Thanks for the article! I hope the author does not mind if I use it for my course work!...

# BgNTGCzqnJLvSjm 2011/10/18 17:31 http://www.software-stock.com/brand/adobe
I read and feel at home. Thanks the creators for a good resource..!

# BaewbvovlN 2011/11/02 5:16 http://www.pharmaciecambier.com/
The topic is pretty complicated for a beginner!...

# UeJWRkinbwGd 2011/11/02 6:09 http://optclinic.com/
It's straight to the point! You could not tell in other words! :D

# DMfQFuIMnDCvwpwcrul 2011/11/07 19:53 http://www.farmaciaunica.com/
Totally agree with you, about a week ago wrote about the same in my blog..!

# EePLEVEsFHZvvRRuMz 2011/11/08 16:01 http://aphrodisiaquesnaturel.com
Good day! I do not see the conditions of using the information. May I copy the text from here on my site if you leave a link to this page?!...

# vVAMWRNWcOxXieLAuhb 2011/11/09 6:10 http://aphrodisiaquesnaturel.com
Good! Wish everybody wrote so:D

A unique note..!

# oXZKtMviTjCwcI 2011/11/16 3:48 http://www.laurenslinens.com/newtod.html
Hello! Read the pages not for the first day. Yes, the connection speed is not good. How can I subscribe? I would like to read you in the future!...

Post Feedback

タイトル
名前
Url:
コメント: