2010年12月5日 星期日

# (stringizing) and ##(merging) operator

#include <stdio.h>


// reference "多型與虛擬" p.184~185 (author 侯捷)

// # (stringizing operator): 將巨集參數轉換為字串常數
#define stringer(x) printf(#x "\n")

// ## (merging operator or token-pasting operator): 把兩個 token 合併成一個 token 再交由編譯器去 parsing
#define paster(n) printf("token" #n "=%d",token##n)


void test_stringer()
{
stringer(hello    world);
}

void test_paster()
{
int token9 = 9;
paster(9);
}

int main()
{
test_stringer();
test_paster();
}

2010年9月30日 星期四

Command DP 實作選單 by Boost Lambda



一個多月沒寫 C++ 程式了,最近有個小案子,需要將 "para.dat" 之類的二進位檔案讀取出來,
在對其中的參數做些設定。

"para.dat" 中內涵

#pragma pack(push,1)
typedef struct _PARA
{
short open_interval;
short unlock_interval; 
.....   // bla bla..
}PARA;
#pragma pack(pop)

之類的資料結構。

基本的想法是做個選單

====================
1)  load para                   // 宣告一個 struct Para 並將 para.dat Load 到  Para
2)  change open_interval  
3)  change unlock_interval
4)  bla bal...
w) write back to para.dat  // 將變更後的 Para 寫回 para.dat
=====================

然後用 switch(n){
         case 1:
            loaod_para();
            break;
          ....
         }
這樣的方式做出來。   
我大概花了半小時的時間寫好~

就想用 Command 設計模式  (將函式產生和函式呼叫解耦) 來重寫,
用 Command 設計模式的話,就可以用 macro 的方式,一次執行多道指令,並且實作 undo 的功能 

我就用了 boost lambda 的方式實作  (參考 beyond the C++ standard library)


以下是我在寫的時候推導的一些範例,分享一下

// copy from << beyond c++ >>
class command
{
    boost::function<void()> f_;
public:
    command() {}
    command(boost::function<void()> f) : f_(f) {}
    void execute()
    {
        if(f_)
        {
            f_();
        }
    }
    template<typename Func>
    void set_function(Func f)
    {
        f_ = f;
    }
    bool enable() const
    {
        return f_;
    }
};

//  use map to invoke command
//  such as command_map["1"].execute()
map<string,command>  command_map;


void menu()
{
    cout << "==============================================\n";
    cout << "command demo";
    cout << "==============================================\n";
    cout << "1. direct say hello\n";
    cout << "2. say hello using _1 \n";
    cout << "3. say what you type\n";
    cout << "h. greet at someone\n";
    cout << "w. write to file 'new_para.dat'\n";
}


// this add concrete command to map: command_map
void init_command()
{
      command_map["1"] = command(  (cout << constant("hello")) );        //  基本的 lambda 用法
      command_map["2"] = command(  bind( &(cout << boost::lambda::_1), "hello" )  );        
      // 因為 command 只接收 void() ,所以要用 bind 將參數綁定,也就是有這個函式讓 command 模式很好用
      
      command_map["3"] = command( bind(& (cin >> boost::lambda::_1 , cout <<  boost::lambda::_1) , string() ) );
      // 這一步我試了很久,原本用  (*istream_iterator<string>(cin)) 得到輸入
      // 但這樣會在 init_command 時就叫你輸入而不是在選單選 3 時。
      // 後來發現用 , 這個運算子將 expression 分開就解決這個問題
      // 我還試過  bind(&(cout << (cin >> _1))) 

 int n = 1;
       command_map["3"] = command(
                           bind((switch_statement(
                                     boost::lambda::_1,
                                     case_statement<0> ( var(cout)<< "I" ),
                                     case_statement<1> ( var(cout)<< "am" ),
                                     case_statement<2> ( var(cout)<< "a" ),
                                     case_statement<3> ( var(cout)<< "boy" ),
                                     default_statement  (var(cout)<< "error people")
                                 )
                                ),n)
                       );
        // 這個我也試了很久 = ="    


}


int main()
{
    init_command();
   
    while(1)
    {
        system("cls");
        menu();
        cout << "choose:";
        string i; cin >> i;
        command_map[i].execute();     //  invoker
        system("pause");
    }
    return 0;
}



有了這些基礎設施,就可以實作像是 macro , undo 的動作了
若是比較複雜的選項,就用函數實作在 assign 給 command_map
eq.

void write_log()
{
  .... bla bla

void init_command()
{
  command_map["w"] = command(write_log);
}

若是函式需要參數勒,  
eq.  void write_log(string filename){...}
用 bind 就對了 XD

 
我 try 的方法先從小的開始寫起,
例如:
      (cout << _1) ("hello");  
      這個 work 後,因為他有一個參數,所以我用 function 來試
      boost::function<void (int) > f = (cout << _1);
      這也 OK 後,利用 bind 去參數
      boost::function<void () > f = bind(&(cout << _1),"hello");
      這個 compile 能過後,就可以加入 command_map 啦

這是我使用 Lambda 配合 Command DP 的小小感想
給大家參考
謝謝^^

    


















Command DP 實作選單 by Boost Lambda



一個多月沒寫 C++ 程式了,最近有個小案子,需要將 "para.dat" 之類的二進位檔案讀取出來,
在對其中的參數做些設定。

"para.dat" 中內涵

#pragma pack(push,1)
typedef struct _PARA
{
short open_interval;
short unlock_interval; 
.....   // bla bla..
}PARA;
#pragma pack(pop)

之類的資料結構。

基本的想法是做個選單

====================
1)  load para                   // 宣告一個 struct Para 並將 para.dat Load 到  Para
2)  change open_interval  
3)  change unlock_interval
4)  bla bal...
w) write back to para.dat  // 將變更後的 Para 寫回 para.dat
=====================

然後用 switch(n){
         case 1:
            loaod_para();
            break;
          ....
         }
這樣的方式做出來。   
我大概花了半小時的時間寫好~

就想用 Command 設計模式  (將函式產生和函式呼叫解耦) 來重寫,
用 Command 設計模式的話,就可以用 macro 的方式,一次執行多道指令,並且實作 undo 的功能 

我就用了 boost lambda 的方式實作  (參考 beyond the C++ standard library)


以下是我在寫的時候推導的一些範例,分享一下

// copy from << beyond c++ >>
class command
{
    boost::function<void()> f_;
public:
    command() {}
    command(boost::function<void()> f) : f_(f) {}
    void execute()
    {
        if(f_)
        {
            f_();
        }
    }
    template<typename Func>
    void set_function(Func f)
    {
        f_ = f;
    }
    bool enable() const
    {
        return f_;
    }
};

//  use map to invoke command
//  such as command_map["1"].execute()
map<string,command>  command_map;


void menu()
{
    cout << "==============================================\n";
    cout << "command demo";
    cout << "==============================================\n";
    cout << "1. direct say hello\n";
    cout << "2. say hello using _1 \n";
    cout << "3. say what you type\n";
    cout << "h. greet at someone\n";
    cout << "w. write to file 'new_para.dat'\n";
}


// this add concrete command to map: command_map
void init_command()
{
      command_map["1"] = command(  (cout << constant("hello")) );        //  基本的 lambda 用法
      command_map["2"] = command(  bind( &(cout << boost::lambda::_1), "hello" )  );        
      // 因為 command 只接收 void() ,所以要用 bind 將參數綁定,也就是有這個函式讓 command 模式很好用
      
      command_map["3"] = command( bind(& (cin >> boost::lambda::_1 , cout <<  boost::lambda::_1) , string() ) );
      // 這一步我試了很久,原本用  (*istream_iterator<string>(cin)) 得到輸入
      // 但這樣會在 init_command 時就叫你輸入而不是在選單選 3 時。
      // 後來發現用 , 這個運算子將 expression 分開就解決這個問題
      // 我還試過  bind(&(cout << (cin >> _1))) 

 int n = 1;
       command_map["3"] = command(
                           bind((switch_statement(
                                     boost::lambda::_1,
                                     case_statement<0> ( var(cout)<< "I" ),
                                     case_statement<1> ( var(cout)<< "am" ),
                                     case_statement<2> ( var(cout)<< "a" ),
                                     case_statement<3> ( var(cout)<< "boy" ),
                                     default_statement  (var(cout)<< "error people")
                                 )
                                ),n)
                       );
        // 這個我也試了很久 = ="    


}


int main()
{
    init_command();
   
    while(1)
    {
        system("cls");
        menu();
        cout << "choose:";
        string i; cin >> i;
        command_map[i].execute();     //  invoker
        system("pause");
    }
    return 0;
}



有了這些基礎設施,就可以實作像是 macro , undo 的動作了
若是比較複雜的選項,就用函數實作在 assign 給 command_map
eq.

void write_log()
{
  .... bla bla

void init_command()
{
  command_map["w"] = command(write_log);
}

若是函式需要參數勒,  
eq.  void write_log(string filename){...}
用 bind 就對了 XD

 
我 try 的方法先從小的開始寫起,
例如:
      (cout << _1) ("hello");  
      這個 work 後,因為他有一個參數,所以我用 function 來試
      boost::function<void (int) > f = (cout << _1);
      這也 OK 後,利用 bind 去參數
      boost::function<void () > f = bind(&(cout << _1),"hello");
      這個 compile 能過後,就可以加入 command_map 啦

這是我使用 Lambda 配合 Command DP 的小小感想
給大家參考
謝謝^^

    


















2010年8月5日 星期四

Codeblocks Setup with GCC 4.5.0



1. 下載 TDM's GCC 4.5.0




  • 第一次安裝時選擇 Create


  • 若是 32 bit 電腦,選擇 MinGW/TDM (32-bit)


  • 選擇安裝路徑,建議不要用預設的。我安裝在 c:\dev\MinGW32 目錄下。


  • 選擇下載點 (我選的是台灣中央大學 應該吧...XD)


  • 選擇安裝元件,一般預設值就可以了。若要編譯 ada 、 objc 等,就要在 gcc 選項勾選相關的元件。


  • 安裝完後,會有 README 文件,可以看一看。裡面有此版本要注意的事項說明。





2. 安裝 codeblocks


  • 選擇 codeblocks-10.05-setup.exe 版本 (mingw 在第一步驟中已經裝了,codeblocks 包含的 mingw 是 GCC 3.4.5 版)


  • 選擇元件 (全選就對了 XD)


  • 設定安裝目錄,我設在 c:\dev\CodeBlocks


  • 若安裝了 TDM's GCC 4.5.0,codeblocks 會自動偵測 (否則就要手動設定 toolchain 有點麻煩)


  • 接下來開始使用 Codeblocks 啦 (簡稱 CB),首先開啟一個 Console Application


  • 為專案配置目錄



  • 把這段 code 貼上 (測試 C++0x 的 Lambda expression 功能)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
vector<string> v;
v.push_back("Be");
v.push_back("whatever");
v.push_back("you");
v.push_back("want");
v.push_back("to");
v.push_back("be.");
sort(v.begin(),v.end(),[](const string& lhs,const string& rhs){
return lhs.size() < rhs.size();
}
);
return 0;
}



  • 按下 Build,這時候會有 error ,不過錯誤訊息會提醒你要勾選 Compiler 選項 -std=c++0x


  • 那就照著做吧!! Setting -> Compiler and Debugger


  • 接下來在 Build 就可以成功了。


Scott Meyers 這篇 blog 介紹了 GCC 4.5 的更新特色,可以參考
http://scottmeyers.blogspot.com/2010/07/updated-c0x-feature-availability.html

Enjoy It ~ \( ̄︶ ̄)>

2010年7月28日 星期三

NetBeans 使用 Boost

在 Visual Studio 2008 中使用 Boost 需要設定 Include Path
我的設定為: D:\dev\boost\boost_1_42_0

如下圖:


而在 NetBeans IDE 中,我也這樣設定,但是 compile 卻失敗,
花了我一個下午在查詢原因。 結論是它的斜線要反過來 @@"
D:\dev\boost\boost_1_42_0 ==> D:/dev/boost/boost_1_42_0
如下圖:



2010年7月6日 星期二

Effective C++ 條款心得

Table of Contents:

1. Accustoming Yourself to C++.

Item 1: View C++ as a federation of languages.

Item 2: Prefer consts, enums, and inlines to #defines.

Item 3: Use const whenever possible.

Item 4: Make sure that objects are initialized before they're used.

2. Constructors, Destructors, and Assignment Operators.

Item 5: Know what functions C++ silently writes and calls.

Item 6: Explicitly disallow the use of compiler-generated functions you do not want.

Item 7: Declare destructors virtual in polymorphic base classes.

Item 8: Prevent exceptions from leaving destructors.

Item 9: Never call virtual functions during construction or destruction.

Item 10: Have assignment operators return a reference to this.

Item 11: Handle assignment to self in operator=.

Item 12: Copy all parts of an object.

3. Resource Management.

Item 13: Use objects to manage resources.

Item 14: Think carefully about copying behavior in resource-managing classes.

Item 15: Provide access to raw resources in resource-managing classes.

Item 16: Use the same form in corresponding uses of new and delete.

Item 17: Store newed objects in smart pointers in standalone statements.

4. Designs and Declarations.

Item 18: Make interfaces easy to use correctly and hard to use incorrectly.

Item 19: Treat class design as type design.

Item 20: Prefer pass-by-reference-to-const to pass-by-value.

Item 21: Don't try to return a reference when you must return an object.

Item 22: Declare data members private.

Item 23: Prefer non-member non-friend functions to member functions.

Item 24: Declare non-member functions when type conversions should apply to all parameters.

Item 25: Consider support for a non-throwing swap.

5. Implementations.

Item 26: Postpone variable definitions as long as possible.

Item 27: Minimize casting.

Item 28: Avoid returning "handles" to object internals.

Item 29: Strive for exception-safe code.

Item 30: Understand the ins and outs of inlining.

Item 31: Minimize compilation dependencies between files.

6. Inheritance and Object-Oriented Design.

Item 32: Make sure public inheritance models "is-a."

Item 33: Avoid hiding inherited names.

Item 34: Differentiate between inheritance of interface and inheritance of implementation.

Item 35: Consider alternatives to virtual functions.

Item 36: Never redefine an inherited non-virtual function.

Item 37: Never redefine a function's inherited default parameter value.

Item 38: Model "has-a" or "is-implemented-in-terms-of" through composition.

Item 39: Use private inheritance judiciously.

Item 40: Use multiple inheritance judiciously.

7. Templates and Generic Programming.

Item 41: Understand implicit interfaces and compile-time polymorphism.

Item 42: Understand the two meanings of typename.

Item 43: Know how to access names in templatized base classes.

Item 44: Factor parameter-independent code out of templates.

Item 45: Use member function templates to accept "all compatible types."

Item 46: Define non-member functions inside templates when type conversions are desired.

Item 47: Use traits classes for information about types.

Item 48: Be aware of template metaprogramming.

8. Customizing new and delete.

Item 49: Understand the behavior of the new-handler.

Item 50: Understand when it makes sense to replace new and delete.

Item 51: Adhere to convention when writing new and delete.

Item 52: Write placement delete if you write placement new.

9. Miscellany.

Item 53: Pay attention to compiler warnings.

Item 54: Familiarize yourself with the standard library, including TR1.

Item 55: Familiarize yourself with Boost.

Appendix A: Beyond Effective C++.