posts - 23,  comments - 94,  trackbacks - 0
 
/************************************************************************/
/* Copyright (c) 2009, Roc King
All rights reserved.

Redistribution and use in source and binary forms,
    with or without modification, are permitted
    provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and other materials provided with the distribution.

3. Neither the name of the Tju nor the names of its contributors
    may be used to endorse or promote products derived from this software
    without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
    AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                                     
*/
/************************************************************************/


/**
这份代码详细介绍了使用SFINAE技术实现is_not_buildin_type的原理。
按顺序由上往下阅读即可。
*/

#include 
<stdio.h>
#include 
<iostream>


/** ------------------------------------------------------------------------ */
#define DEFINITION(prefix)          \
prefix none {};                     \
prefix data { 
int i; };             \
prefix function { 
void f(int ) {} };    \
prefix both { 
int i; double f() { return 0.0; } };

namespace structures { DEFINITION(struct) }
namespace s = structures;

namespace classes { DEFINITION(class) }
namespace c = classes;

namespace unions { DEFINITION(union) }
namespace u = unions;

#undef DEFINITION

/**
上面对class、struct、union分别定义了:
none        有数据成员,无成员函数
data        有数据成员,没成员函数
function    无数据成员,有成员函数
both        有数据成员,有成员函数
*/

/** ------------------------------------------------------------------------ */

void test_pointer_to_data_member() {

    
// 一旦某个类型不是基本数据类型,就可以定义成员指针(数据成员指针,成员函数指针)。
    
// 即使它没有数据成员或者成员函数。

    
// s::none 并没有数据成员或者成员函数。
    int s::none::* p; //但是可以定义一个指向s的数据成员指针,只要类型不是void
    
// void s::none::* p2; //error C2182: 'p2' : illegal use of type 'void'

    
// 同时,在C++中,字面值0可以隐式转换到任何指针类型。
    p = 0// ok
    double s::none::* p3 = 0// ok

    
// 但是,如果某类型没有对应类型的数据成员,就不能用数据成员指针去指向它。
    int s::data::* p4 = 0;
    p4 
= &s::data::i;  // ok
    double s::data::* p5 = 0;
    
// p5 = &s::data::i;
    
// error C2440: '=' : cannot convert from 'int structures::data::* ' to 'double structures::data::* '

    (
void)p3; (void)p5;
}

// 这个是比较完整的测试
void test_pointer_to_data_member_integrate();


/** ------------------------------------------------------------------------ */

void test_pointer_to_member_function() {
    
// 同理,一旦某个类型不是基本类型,就可以定义指向该类型的成员函数的指针。
    
// 并且字面值0可以隐式转换到该指针。

    
int (u::none::* p1)(void)  = 0;
    
double (u::none::* p2)(double= 0;

    
// 如果该类型确实有匹配的成员函数,可以使用该成员函数给指针赋值。
    double (u::both::* p3 )(void= &u::both::f;
    
void (u::function::* p4)(int= &u::function::f;

    
// 否则不能赋值
    
// double (u::both::* p5 )(void) = &u::function::f;
    
//error C2440: 'initializing' : cannot convert from 'void (__thiscall unions::function::* )(int)' to 'double (__thiscall unions::both::* )(void)'
    
// void (u::function::* p6)(int) = &u::both::f;
    
//error C2440: 'initializing' : cannot convert from 'double (__thiscall unions::both::* )(void)' to 'void (__thiscall unions::function::* )(int)'

    (
void)p1; (void)p2; (void)p3; (void)p4;
}

// 这个是比较完整的测试
void test_pointer_to_member_function_integrate();

/** ------------------------------------------------------------------------ */
/**
那么,测试一个类型是否是内建类型的“一个”方法就是
*/

namespace SFINAE {

    
class true_type { char dummy; true_type(); };
    
class false_type { char dummy[2]; false_type(); };
    
// sizeof(true_type)!=sizeof(false_type)

    template
<class C>
    true_type is_not_buildin_type_test(
int C::* pointer_to_data_member);

    template
<typename T>
    false_type is_not_buildin_type_test();

    
void test_theory() {
        
using namespace std;

        
/* 在当前名字空间下, is_not_buildin_type_test是2个函数模板的名字:
        template<class C>
        true_type is_not_buildin_type_test(int C::* pointer_to_data_member);
        (以下简称模板1)

        template<typename T>
        false_type is_not_buildin_type_test();
        (以下简称模板2)

        它们相互构成重载。
        
*/

        cout
<<sizeof( is_not_buildin_type_test<c::none>(0) )<<endl;
        
// 0 可以隐式转化成 int c::none::* ,可以匹配模板1 (with C = c::none)

        
// 这里int是无关紧要的, 只要不是void就行
        
// 当然使用其他类型的数据成员指针 T C::* (T!=void)
        
// 或者成员函数指针进行测试 T (C::*)(paramter_list),也是可以的
        
// 只是int C::* 写起来比较方便。

        
// 因为() 可以匹配任何类型的对象,
        
// 所以 0 也可以匹配模板2

        
// 又因为()处于重载选择优先级中的最底层,所以最终匹配模板1。
        
// 注意,此处模板2不能使用(int),或者(T*)因为它的优先级高于(int C::*)


        cout
<<sizeof( is_not_buildin_type_test<double>(0) )<<endl;
        
// 0 不能隐式转换成 int double::*,也就不能匹配模板1 ( with C=double )

        
// 但是还有一个“补救”的函数模板2,可以匹配任何类型的对象。
        
// 又因为SFINAE(Substitution failure is not an error)机制
        
// 所以对模板1的失败的匹配并不报错。
    }

    
// 还有一些细节
    
// 比如is_not_buildin_type_test并没有实现。
    
// 但是因为它同时也没有被调用, 而仅仅是用sizeof测试它的返回值,所以不算错误。
    
// 也防止了客户无意调用这个函数。

    
// 如何得知哪个is_not_buildin_type_test被重载选中?
    
// 是通过返回值的大小不同来区分的。

    
// 所以就需要true_type和false_type这2个东西。
    
// 其实更合理的命名应该是small_type和big_type。
    
// 同时,它们声明有私有的构造函数,并且不实现,防止客户使用这2个类。

    
// 还因为is_not_buildin_type_test并没有真正实现
    
// 也就没有真正返回true_type或者false_type
    
// 所以没有实现true_type和false_type的构造函数也没关系。

    
// 一切都因为sizeof ……

    
/** -------------------------------------------------------------------- */
    
/**
    将这种方法再包装一下
    (避免客户去使用sizeof( xxx ) == sizeof( ture_type )等等)
    就得到
    
*/

    template
<typename T>
    
class is_not_buildin_type {
        is_not_buildin_type();
    
public:
        
enum { value =
            
sizeof(true_type)==sizeof( is_not_buildin_type_test<T>(0) ) };
    };
    
// 或者将true_type,false_type,定义为它的内嵌类型。
    
// 同时将is_not_buildin_type_test定义为它的静态成员函数。

    template
<typename T>
    
class is_not_buildin_type2 {
        is_not_buildin_type2();

        
// 因为是内嵌的private,客户不能访问
        
// 所以可以随意一点
        typedef char small_t;
        
struct big_t { small_t dummy[2]; };

        template
<typename U>
        
static big_t test(void (U::*)(shortfloat) );
        
// 只要是成员指针就ok,无论是数据成员指针还是成员函数指针。
        
// 也无论类型,签名如何。

        template
<typename U>
        
static small_t test();
        
// 注意补救函数现在返回small_t

    
public:
        
// 但这也是无关紧要的,因为small_t和big_t只是告之哪个重载被选中的方式。
        
// 只要这里处理好对应就可以了。
        enum { value= sizeof(big_t)==sizeof( test<T>(0) ) };
    };

    
void test_wrapper() {
        
using namespace std;
        cout
<<is_not_buildin_type<c::data>::value<<endl;
        cout
<<is_not_buildin_type<u::both>::value<<endl;
        cout
<<is_not_buildin_type<float>::value<<endl;

        cout
<<is_not_buildin_type2<c::data>::value<<endl;
        cout
<<is_not_buildin_type2<u::both>::value<<endl;
        cout
<<is_not_buildin_type2<float>::value<<endl;
    }

    
// 一个更完整的测试
    void test_wrapper_integrate();
}

/** ------------------------------------------------------------------------ */
/**测试一个类型是否是内建类型的另一个方法,需要更少的技巧。*/

namespace partial_specialization {

    template
<typename T>
    
struct is_not_buildin_type { enum { value=true }; };
    
// T不是一个内建类型

    
// 除非
    template<>
    
struct is_not_buildin_type<int> { enum { value=false}; };
    
// T是int
    template<>
    
struct is_not_buildin_type<unsigned int> { enum { value=false}; };
    
// T是unsigned int
    
// .. more ..
}

int main()
{
    
using namespace std;
    test_pointer_to_data_member();
    test_pointer_to_data_member_integrate();
    test_pointer_to_member_function();
    test_pointer_to_member_function_integrate();

    cout
<<endl;
    SFINAE::test_theory();
    cout
<<endl;
    SFINAE::test_wrapper();
    cout
<<endl;
    SFINAE::test_wrapper_integrate();
}



void test_pointer_to_data_member_integrate() {
    
// to do
}
void test_pointer_to_member_function_integrate() {
    
// to do
}

namespace SFINAE {
    
void test_wrapper_integrate() {
        
// to do
    }
}

这个代码已经能很完美的解释了~
今天看了C++ Templates 的15章.. 收获颇多.. 以前的很多疑惑都比较开朗了~

posted @ 2009-03-16 23:32 Charlie 侯杰 阅读(2638) | 评论 (3)编辑 收藏
 1 #include <iostream>
 2 #include <boost/shared_ptr.hpp>
 3 #include <boost/enable_shared_from_this.hpp>
 4 
 5 using namespace std;
 6 
 7 class A : public boost::enable_shared_from_this<A>
 8 {
 9 public:
10     boost::shared_ptr<A> child_;
11     boost::shared_ptr<A> parent_;
12 
13     void add(boost::shared_ptr<A> child)
14     {
15         child_ = child;
16         child_->set(shared_from_this());
17     }
18 
19     void set(boost::shared_ptr<A> parent)
20     {
21         parent_ = parent;
22     }
23 };
24 
25 int main()
26 {
27     boost::shared_ptr<A> p1(new A);
28     boost::shared_ptr<A> p2(new A);
29 
30     p1->add(p2);
31 
32     cout<<p1<<endl;
33     cout<<p2<<endl;
34     cout<<p1->child_<<endl;
35     cout<<p2->parent_<<endl;
36     cout<<p1.use_count()<<endl;
37     cout<<p2.use_count()<<endl;
38 
39     return 0;
40 }

有了shared_from_this.. 我泪流满面
之前不知道这个的时候..用了很愚蠢的做法

void add(shared_ptr<A> child)
    child_ = child;
    child_->set(shared_ptr<A>(this));
}
结果错误连连~ 然后放弃使用shared_ptr... 用raw_ptr...

顺便推荐这本书
beyond_stl_cn.chm

放到了我的SVN上.. 一本很好的介绍Boost如何使用的书..

http://code.google.com/p/charlib/source/browse/trunk/Boost%20Book/Beyond_STL_cn.rar

进入页面后点右下的 view raw file 就可以下载了

以上是早上写的.. 写好后很高兴的发布了.. 但是后来发现上面这段程序非常的白痴
最关键的就在于,其实这上面的两个shared_ptr已经循环引用了.. 再也没有办法自动解开
资源也就套死在了原地.. Oh My God... 居然愚蠢到这种地步..

然后才发现.. weak_ptr 一点都不weak.. 这里就需要用weak_ptr来处理!

换成下面这个...
#include <iostream>
#include 
<boost/shared_ptr.hpp>
#include 
<boost/weak_ptr.hpp>
#include 
<boost/enable_shared_from_this.hpp>

using namespace std;

class A : public boost::enable_shared_from_this<A>
{
public:
    A(
const int id) : id_(id) { cout<<id_<<" Constructed!"<<endl; }
    
~A() { cout<<id_<<" Destructed!"<<endl; }

    
int id_;
    boost::shared_ptr
<A> child_;
    boost::weak_ptr
<A> parent_;

    
void add(boost::shared_ptr<A> child)
    {
        child_ 
= child;
        child_
->set(shared_from_this());
    }

    
void set(boost::shared_ptr<A> parent)
    {
        parent_ 
= parent;
    }

    boost::shared_ptr
<A> get_parent()
    {
        
return parent_.lock();
    }
};

int main()
{
    boost::shared_ptr
<A> p1(new A(1));
    boost::shared_ptr
<A> p2(new A(2));

    p1
->add(p2);

    
return 0;
}

通过这个测试..
输出的结果是
1 Construct
2 Construct
1 Destruct
2 Destruct

这样的输出并不奇怪. 因为 weak_ptr 是 shared_ptr 的观察者,将 shared_ptr 传给 weak_ptr 不会增加 shared_ptr的引用计数. 所以这里的操作, p2 的引用计数是2, p1 的引用计数是1, 所以p1是unique的,p1先析构,p2的引用计数-1,然后析构.

不过这里资源的析构顺序可能不是我们关心的范围,我这里认为把资源丢给智能指针这类物件管理后,主要是为了资源不泄漏,资源的析构顺序如果在关心的范围,也就该自己管理该资源了.

自己犯的一个低级错误,赶忙把帖子存草稿了. 现在弄清楚怎么处理后,才敢发上来,呵呵~ ^ ^

posted @ 2009-03-12 19:20 Charlie 侯杰 阅读(8875) | 评论 (4)编辑 收藏
为了达到泛型和范维.. 用模板定义了维数和数据类型
Vector使用std::valarray
Matrix使用Vector

Matrix实际上还没有完成.. 留下了比较难的 求逆阵的运算..
晚上在写transpose的时候也发现..
Matrix<m,n> 要转置就会变成 Matrix<n,m>
由于模板实现的问题,好像不能让自身转置...改变自身的维度

具体见:

http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/Vector.hpp

http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/Matrix.hpp

不过很少有这么长篇的使用过模板写东西.. 还是算一次比较不错的练习~

posted @ 2009-03-10 00:41 Charlie 侯杰 阅读(1105) | 评论 (7)编辑 收藏
嗯.. SVN上上传PlayerState.cbp
该工程实现 State 设计模式

具体如下...

 1 //forward decl
 2 class PlayerState;
 3 
 4 class Player
 5 {
 6 public:
 7     Player(PlayerState* initState);
 8 
 9     void walk();
10     void stand();
11     void jump();
12 
13     void setState(PlayerState* state);
14 protected:
15     PlayerState* mState;
16 
17     //decl uncopyable
18     Player(const Player& player);
19     Player& operator=(const Player& rhs);
20 };
21 

玩家的行为转由状态对象处理

//forward decl
class Player;

class PlayerState
{
public:
    
virtual void walk(Player* player) = 0;
    
virtual void stand(Player* player) = 0;
    
virtual void jump(Player* player) = 0;
};

class Walking : public PlayerState
{
public:
    
void walk(Player* player);
    
void stand(Player* player);
    
void jump(Player* player);

    
static Walking* getInstancePtr();
protected:
    
//singleton
    Walking();

    
static Walking* mInstance;
};

class Standing : public PlayerState
{
public:
    
void walk(Player* player);
    
void stand(Player* player);
    
void jump(Player* player);

    
static Standing* getInstancePtr();
protected:
    Standing();

    
static Standing* mInstance;
};

class Jumping : public PlayerState
{
public:
    
void walk(Player* player);
    
void stand(Player* player);
    
void jump(Player* player);

    
static Jumping* getInstancePtr();
protected:
    Jumping();

    
static Jumping* mInstance;
};

相对比较简单... 可以当一个非常无聊的文字MUD来玩..

具体见
http://code.google.com/p/charlib/source/browse/trunk/
下的 PlayerState 文件夹

posted @ 2009-03-02 18:05 Charlie 侯杰 阅读(1332) | 评论 (2)编辑 收藏
前两天某C++群正好在讨论C++中int类型的长度
对于支持C99标准的编译器来说,可以#include <cstdint>
来使用 int32_t, 但是目前不少的编译器都做不到这点
所以,自己写了个IntType.hpp

 1 #ifndef INTTYPE_HPP_
 2 #define INTTYPE_HPP_
 3 
 4 #include "Platform.hpp"
 5 
 6 namespace Charlie
 7 {
 8 
 9 typedef long long int64_t;
10 typedef int       int32_t;
11 typedef short     int16_t;
12 typedef char      int8_t;
13 
14 typedef unsigned long long uint64_t;
15 typedef unsigned int       uint32_t;
16 typedef unsigned short     uint16_t;
17 typedef unsigned char      uint8_t;
18 
19 }
20 
21 #endif // INTTYPE_HPP_
22 

然后今天大部分时间都消耗在了Timer的跨平台处理上

这里采用了Bridge Design Pattern
即pImpl方法,实现了Linux 和 Windows 两个平台相关的高精度计时器
接口设计得很简单,只能得到计时器定义以来经过的时间(单位是毫秒 //虽然精度都高于毫秒)

具体请见一下几个文件了

http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/Timer.hpp
http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/TimerImpl.hpp
http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/LinuxTimerImpl.hpp
http://code.google.com/p/charlib/source/browse/trunk/Charlib/includes/Win32TimerImpl.hpp
以及对应的srcs下的.cpp文件

基本上是这样

Timer {
protected:
    TimerImpl* pImpl;
}

class LinuxTimerImpl : public TimerImpl {}
class Win32TimerImpl : public TimerImpl {}

还定义了一个用于多平台多编译器的平台辨识头文件 - Platform.hpp

目前SVN上也有VC 05的工程 和 Code::Blocks 的工程文件
代码在Windows下 MINGW 和 MSVC 8 两个编译器上编译通过
在Ubuntu下使用Code::Blocks + GCC 编译器上通过

// fibonacci数列的模板元编程版本因为在Ubuntu下GCC编译未通过,所以注释掉了,但是在MSVC 8和Code::Blocks的MINGW下编译通过

SVN地址: http://charlib.googlecode.com/svn/trunk/

其他杂项:
    HugeInt added 预计在有空的时候会完成,用于高精度整形的运算 = =~!

posted @ 2009-03-01 21:15 Charlie 侯杰 阅读(1929) | 评论 (4)编辑 收藏
在Google上建了一个自己的SVN
想用来把自己的习作存一存

这学期开了算法课,可能会有很多C++实作的算法练习
还有一些设计模式的练习
可能还有一些杂项

还有一个目标就是能写出平台无关的代码
还在努力中……

目前使用 Visual C++ 2008 Express 版本的工程
以后可能会使用Code::Blocks来做

估计除了DirectX的练习部分,其他都会平台无关

地址:
    http://code.google.com/p/charlib/

Charlib 是 Charlie + lib 的意思,不是 字符 - 库 ~

昨天在研究斐波那契数列,还需要完善
目前写了比较基础的

NonCopyable
    用于规定无法复制的类
Timer
    *依赖WindowsAPI的高精度计时器,精度超过ms

Fibonacci数列
    模板元编程 版本
    递归求解版本
    递推求解版本

posted @ 2009-03-01 10:29 Charlie 侯杰 阅读(223) | 评论 (0)编辑 收藏
初见这个内容是在Effective C++上,在构造函数和析构函数中调用虚函数是非常不好的行为一个简单的例子 class Base{public:    Base()    {        cout
文章来源:http://blog.csdn.net/huntrose/archive/2008/11/06/3230766.aspx
posted @ 2009-03-01 10:16 Charlie 侯杰 阅读(166) | 评论 (0)编辑 收藏
C++
文章来源:http://blog.csdn.net/huntrose/archive/2008/11/15/3305351.aspx
posted @ 2009-03-01 10:16 Charlie 侯杰 阅读(155) | 评论 (0)编辑 收藏
#include  using namespace std;class Door{public:    virtual void open() {        cout
文章来源:http://blog.csdn.net/huntrose/archive/2008/11/16/3312184.aspx
posted @ 2009-03-01 10:16 Charlie 侯杰 阅读(219) | 评论 (0)编辑 收藏
指针是C++中不得不谈的一个话题,或许我还不是很能熟练的掌握指针以及我所要讨论的引用计数型指针的全部,但是还是有那么些迫不及待想要表达一下。指针 pointer 是资源泄漏 resource leak 的根源(当然可能还有其他一些什么东西,在我的映像中异常仿佛也会造成资源泄漏)最简单的一个资源泄漏的例子就是new和delete这样的动态内存分配算子没有正确使用造成的:struct A {    A()  { printf("A Constructor!"); }    ~A() { printf("A Destructor!"); }};void area(){    A *p = new A();}执行完 area() 后,自然是只有A构造的消息,而A的析构却不见影踪。这里我们在离开了area作用域后,我们就无法对p所指向之资源进行操作,A的实例就会被悬挂在内存的某处得不到清理。一个形象
文章来源:http://blog.csdn.net/huntrose/archive/2008/11/18/3326388.aspx
posted @ 2009-03-01 10:16 Charlie 侯杰 阅读(115) | 评论 (0)编辑 收藏
仅列出标题
共3页: 1 2 3 
by Charlie