tommy

It's hard to tell the world we live in is either a reality or a dream
posts - 52, comments - 17, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

《windows图形编程》有讲:

KTimer.h

#pragma once
inline unsigned __int64 GetCycleCount(
void )
{
    _asm _emit 
0x0F
    _asm _emit 
0x31
}


class  KTimer  
{
    unsigned __int64 m_startcycle;
public :
    unsigned __int64 m_overhead;    
// RTSC指令的运行时间

    KTimer()
    
{
        m_overhead 
=   0 ;
        Start();
        m_overhead 
=  Stop();
    }

    
void  Start();
    unsigned __int64 Stop();
    unsigned unsigned GetCPUSpeed();

}
;

KTimer.cpp
#include "KTimer.h"

#include 
<iostream>
#include 
<windows.h>


void KTimer::Start()
{
    m_startcycle 
= GetCycleCount();
}

unsigned __int64 KTimer::Stop()
{
    
return GetCycleCount() - m_startcycle - m_overhead;
}

unsigned unsigned KTimer::GetCPUSpeed()
{
    cout 
<< "开始测试 cpu速度.." << endl;
    Start();
    Sleep(
1000);
    unsigned cputime 
= Stop();
    unsigned cpuspeed10 
= (unsigned)(cputime/100000);
    cout 
<< "CPU速度 每秒:" << cputime << " clocks" << endl;
    
return cpuspeed10 == 0 ? 1 : cpuspeed10;
}

用法:
#include "stdafx.h"
#include 
<tchar.h>
#include 
<windows.h>
#include 
<iostream>

#include 
"KTimer.h"

int main(int argc, char* argv[])
{    
    KTimer timer;

    unsigned cpuspeed10 
= timer.GetCPUSpeed();

    timer.Start();
    
//做耗时操作
    
    unsigned time 
= timer.Stop();

    TCHAR mess[
128];
    wsprintf(mess,_T(
"耗时:%d ns"), time * 10000 / cpuspeed10);
    cout 
<< mess << endl;

    
return 0;
}

posted @ 2006-04-01 11:10 Tommy Liang 阅读(818) | 评论 (1)编辑 收藏

范围广阔啊。
1、地图  从A到B,哪条路花费最少 / 哪条是最快的路线,如果身上只能花N$,那么应该选择哪条路?
2、超文本  图处理算法是搜索引擎的基本组成部分
3、电路  如“能否将此电路做在芯片上而不出现任何线路交叉”
4、调度  如何满足给定约束,又节省时间
5、事务   如对通信线路的布线从而高效地处理通信;对市场购销现金流的监测以便加强对市场实际情况的了解。
6、匹配   如应聘人员与单位机构的匹配
7、网络   计算机网络的维护,如何调整节点以便确保某些站点或连接不至于处于太“要害”的地位。
8、程序结构   如何最佳地为程序分配资源以便做到最高效?


值得研究。

posted @ 2006-02-06 09:49 Tommy Liang 阅读(420) | 评论 (0)编辑 收藏

书里面说的这个词:
型别计算的边界标记

NullType只有声明没有定义。

class NullType;
这是为了表达“我不是个令人感兴趣的型别”,可以作为“找不到型别”的消息标记。类似\0这样。

EmptyType,就是一个空类
struct EmptyType {};

这是可被继承的合法型别,可以作为template的缺省参数型别。

posted @ 2006-02-06 01:29 Tommy Liang 阅读(895) | 评论 (0)编辑 收藏

std::type_info类可以在执行期间查询对象型别,但使用起来比较麻烦。为此定义了wrapper

下面的代码出自 Loki库:
总得来说是提供了std::type_info的所有成员函数;
提供了value语义,即public copy构造函数和public assignment操作符;
定义了 operator< 和 operator== 等

namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class TypeInfo
// Purpose: offer a first-class, comparable wrapper over std::type_info
////////////////////////////////////////////////////////////////////////////////

    
class TypeInfo
    
{
    
public:
        
// Constructors
        TypeInfo(); // needed for containers
        TypeInfo(const std::type_info&); // non-explicit

        
// Access for the wrapped std::type_info
        const std::type_info& Get() const;
        
// Compatibility functions
        bool before(const TypeInfo& rhs) const;
        
const char* name() const;

    
private:
        
const std::type_info* pInfo_;
    }
;
    
// Implementation
    
    inline TypeInfo::TypeInfo()
    
{
        
class Nil {};
        pInfo_ 
= &typeid(Nil);
        assert(pInfo_);
    }

    
    inline TypeInfo::TypeInfo(
const std::type_info& ti)
    : pInfo_(
&ti)
    
{ assert(pInfo_); }
    
    inline 
bool TypeInfo::before(const TypeInfo& rhs) const
    
{
        assert(pInfo_);
        
return pInfo_->before(*rhs.pInfo_) != 0;
    }


    inline 
const std::type_info& TypeInfo::Get() const
    
{
        assert(pInfo_);
        
return *pInfo_;
    }

    
    inline 
const char* TypeInfo::name() const
    
{
        assert(pInfo_);
        
return pInfo_->name();
    }


// Comparison operators
    
    inline 
bool operator==(const TypeInfo& lhs, const TypeInfo& rhs)
    
return (lhs.Get() == rhs.Get()) != 0; }

    inline 
bool operator<(const TypeInfo& lhs, const TypeInfo& rhs)
    
return lhs.before(rhs); }

    inline 
bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs)
    
return !(lhs == rhs); }    
    
    inline 
bool operator>(const TypeInfo& lhs, const TypeInfo& rhs)
    
return rhs < lhs; }
    
    inline 
bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs)
    
return !(lhs > rhs); }
     
    inline 
bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs)
    
return !(lhs < rhs); }
}

posted @ 2006-02-06 01:20 Tommy Liang 阅读(4026) | 评论 (0)编辑 收藏

在编译时刻,在Conversion类中产生两个常数(编译器帮忙计算)

template <class T,class U>
class Conversion
{
    
//
public:
    
enum { exists2Way = exists && Conversion<U,T>::exists };
        
enum { sameType = false };
}
;
一个是 exists2Way,表示是否可以两个类型互相转换,
sameType 表示 T和U是否同一个类型。
不过,虽然书里这么说,我怎么都搞不懂为什么这样可以,测试也是不对的,难道这个sameType的写法还有别的奥妙?
不过下面这个偏特的写法倒是比较容易理解:
template <class T>
class Conversion<T,T>
{
public:
    
enum { exists = 1,exists2Way = 1,sameType = 1 };
}
;
这个测试是OK的。

有了这几个常数,要决定两个class之间是否存在继承关系就比较容易了:
#define SUPERSUBCLASS(T,U) \
(Conversion
<const U*const T*>::exists && \
!Conversion<const T*const void*>::sameType)
如果U是public继承自T,或者T和U是同一个类,那么SUPERSUBCLASS(T,U)传回true,这里是把某个class视为自己的超类,更严谨的做法是:
#define SUPERSUBCLASS_STRICT(T,U) \
(SUPERSUBCLASS(T,U) 
&& \
!Conversion<const T, const U>::sameType)
即排除T与U是同一个类型的情况。

另外,加上 const 是为了 防止因为 const 而导致转型失败,对于已经是const的东西再const一次的话后面一次的const会忽略掉。

再,这个宏的名字很清晰,就是 超类--子类, 前面那个T是超类,U是子类,这个命名比 INHERITS要好。

posted @ 2006-02-06 01:11 Tommy Liang 阅读(446) | 评论 (0)编辑 收藏

就是这样一个类:
template <class T,class U>
class Conversion
{
    typedef 
char Small;
    
class Big char dummy[2]; };
    
static Small Test(U);
    
static Big Test();
    
static T MakeT();
public:
    
enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
}
;

关于函数 Small Test(U) 和 Big Test(...) ,书里面说:
。。。需要两个重载函数,其一如先前所说,接受一个U对象并传回一个Small对象:
Small Test(U);
但接下来,我该如何写出一个可接受任何其他种对象的函数呢?。。。。

我觉得这个地方翻译得有点问题,是不是应该说:“。。我该如何写出一个可接受任何另外一种类型(即 T)的对象的函数呢。。”,因为这里就是 T和U嘛, 没有什么“其他种”,这样翻译容易让我迷惑不解了一会儿。

如果接受 U的那个函数被调用,则T可以被转换为 U,否则无法转换,这个是思路的根本。

为什么要做一个 MakeT这样的函数而不直接使用T呢? 这是为了满足当 T 只有私有构造函数的情况,对于编译器来说,sizeof 是在编译期完成评估的,所以,MakeT 里面到底做了什么并不重要,重要的是他返回的类型,是 T,所以,作者很兴奋地说,这是一个 StrawMan function,即“稻草人函数”,哈哈,只是一个样子而已,但是这已经足够了,那两个重载的Test方法也是一样,这里我们不关心他的函数体。强啊,爽歪歪,快感的源泉啊

测试代码如下:
    using namespace std;

    cout 
<< Conversion<doubleint>::exists << ' '
        
<< Conversion<charchar*>::exists << ' '
        
<< Conversion<size_t, vector<int> >::exists << ' ';
输出: 1 0 0
double可以转换为 int
char 不能转换为 char*
vector<int> 是一个容器的构造函数,size_t 不能转换,因为这个构造函数是 explicit的,这个地方还是有点迷糊,还得研究一下。

posted @ 2006-02-05 05:34 Tommy Liang 阅读(745) | 评论 (2)编辑 收藏

简而言之:explicit修饰的构造函数不能担任转换函数

这个 《ANSI/ISO C++ Professional Programmer's Handbook 》是这样说的

explicit Constructors
A constructor that takes a single argument is, by default, an implicit conversion operator, which converts its argument to
an object of its class (see also Chapter 3, "Operator Overloading"). Examine the following concrete example:
class string
{
private:
int size;
int capacity;
char *buff;
public:
string();
string(int size); // constructor and implicit conversion operator
string(const char *); // constructor and implicit conversion operator
~string();
};
Class string has three constructors: a default constructor, a constructor that takes int, and a constructor that
constructs a string from const char *. The second constructor is used to create an empty string object with an
initial preallocated buffer at the specified size. However, in the case of class string, the automatic conversion is
dubious. Converting an int into a string object doesn't make sense, although this is exactly what this constructor does.

Consider the following:
int main()
{
string s = "hello"; //OK, convert a C-string into a string object
int ns = 0;
s = 1; // 1 oops, programmer intended to write ns = 1,
}
In the expression s= 1;, the programmer simply mistyped the name of the variable ns, typing s instead. Normally,
the compiler detects the incompatible types and issues an error message. However, before ruling it out, the compiler first
searches for a user-defined conversion that allows this expression; indeed, it finds the constructor that takes int.
Consequently, the compiler interprets the expression s= 1; as if the programmer had written
s = string(1);
You might encounter a similar problem when calling a function that takes a string argument. The following example
can either be a cryptic coding style or simply a programmer's typographical error. However, due to the implicit
conversion constructor of class string, it will pass unnoticed:
int f(string s);
int main()
{
f(1); // without a an explicit constructor,
//this call is expanded into: f ( string(1) );
//was that intentional or merely a programmer's typo?
}
'In order to avoid such implicit conversions, a constructor that takes one argument needs to be declared explicit:
class string
{
//...
public:
explicit string(int size); // block implicit conversion
string(const char *); //implicit conversion
~string();
};
An explicit constructor does not behave as an implicit conversion operator, which enables the compiler to catch the
typographical error this time:
int main()
{
string s = "hello"; //OK, convert a C-string into a string object
int ns = 0;
s = 1; // compile time error ; this time the compiler catches the typo
}
Why aren't all constructors automatically declared explicit? Under some conditions, the automatic type conversion is
useful and well behaved. A good example of this is the third constructor of string:
string(const char *);

The implicit type conversion of const char * to a string object enables its users to write the following:
string s;
s = "Hello";
The compiler implicitly transforms this into
string s;
//pseudo C++ code:
s = string ("Hello"); //create a temporary and assign it to s
On the other hand, if you declare this constructor explicit, you have to use explicit type conversion:
class string
{
//...
public:
explicit string(const char *);
};
int main()
{
string s;
s = string("Hello"); //explicit conversion now required
return 0;
}
Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. The C++ Standardization
committee was aware of that. In order to not make existing code break, the implicit conversion was retained. However, a
new keyword, explicit, was introduced to the languageto enable the programmer to block the implicit conversion
when it is undesirable. As a rule, a constructor that can be invoked with a single argument needs to be declared
explicit. When the implicit type conversion is intentional and well behaved, the constructor can be used as an
implicit conversion operator.

posted @ 2006-02-05 05:16 Tommy Liang 阅读(9957) | 评论 (6)编辑 收藏

睡不着,继续读书

有时候,范型程序需要根据一个boolean变量来选择某个型别或另一个型别。
下面定义的结构提出了解决方案:
template <bool flag,typename T,typename U>
struct Select
{
    typedef T Result;
}
;
//偏特化
template <typename T,typename U>
struct Select<false,T,U>
{
    typedef U Result;
}
;
也就是说,如果flag是true,则编译器使用第一份定义,即Result被定义为T,
如果是false,则偏特化机制起作用,Result被定义为 U

偏特化真强,全在乎想象力了

posted @ 2006-02-05 04:53 Tommy Liang 阅读(451) | 评论 (0)编辑 收藏

就是这样一个结构:

template <typename T>
struct Type2Type
{
    typedef T OriginalType;    
}
;

假定有个片断如下,创建一个T*
template <class T,class U>
T
* Create(const U& arg)
{
    
return new T(arg);
}

如果对于某个类如“Widget”,其ctor要有两个参数,比如第二个参数必须是-1(对于旧的代码来说,谁知道呢:)),但又不想另外创建一个“CreateWidget”方法,那么怎么办呢,函数是不能偏特化的,即如下代码:
//错误的代码
template <class U>
Widget
* Create<Widget,U>(const U& arg)
{
    
return new Widget(arg,-1);
}
在 VC7下会报告:非法使用显式模板参数

只能使用函数重载,比如:
template <class T,class U>
T
* Create(const U&arg,T /*虚拟*/)
{
   
return new T(arg);
}


template 
<class U>
Widget 
* Create(const U& arg, Widget /*虚拟*/)
{
    
return new Widget(arg,-1);
}

  这样是可以解决问题,但最大的毛病在于运行时构造了 未被使用的对象这个开销(虚拟的Widget参数)。这时 Type2Type 这个咚咚出场了,按照书的说法,这是“一个型别代表物、一个可以让你传给重载函数的轻量级ID”,如下:

template <class T,class U>
T
* Create(const U& arg,Type2Type<T>)
{
    
return new T(arg);
}


template 
<class U>
Widget 
* Create(const U& arg,Type2Type<Widget>)
{
    
return new Widget(arg,-1);
}


调用方:
String 
*pStr = Create("hello",Type2Type<String>());
Widget 
*pW = Create(100,Type2Type<Widget>());

 

关键是,这个东西也是给编译器看的,妙

posted @ 2006-02-05 04:40 Tommy Liang 阅读(1388) | 评论 (1)编辑 收藏

inline unsigned __int64 GetCycleCount(void)
{
   _asm _emit 
0x0F
   _asm _emit 
0x31
}
dasm如下:
:    inline unsigned __int64 GetCycleCount(void)
7:    {
00401070 55                   push        ebp
00401071 8B EC                mov         ebp,esp
00401073 83 EC 40             sub         esp,40h
00401076 53                   push        ebx
00401077 56                   push        esi
00401078 57                   push        edi
00401079 8D 7D C0             lea         edi,[ebp-40h]
0040107C B9 
10 00 00 00       mov         ecx,10h
00401081 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
00401086 F3 AB                rep stos    dword ptr [edi]
8:       _asm _emit 0x0F
00401088 0F 31                rdtsc
10:   }

0040108A 5F                   pop         edi
0040108B 5E                   pop         esi
0040108C 5B                   pop         ebx
0040108D 
83 C4 40             add         esp,40h
00401090 3B EC                cmp         ebp,esp
00401092 E8 19 00 00 00       call        __chkesp (004010b0)
00401097 8B E5                mov         esp,ebp
00401099 5D                   pop         ebp
0040109A C3                   ret
关键就是那个RDTSC指令,即 Read Time Stamp Counter, 结果会保存在EDX:EAX寄存器对中。

Intel的文档是这样说的:
With the Pentium processor, Intel added an additional instruction called RDTSC (Read Time Stamp
Counter). This gives software direct access to the number of clock counts the processor has
experienced since its last power
-on or hardware reset. With contemporary clock rates of, for
example, 
3.06 Ghz, that results in a timing period of only 0.326 nanoseconds.

posted @ 2006-02-04 16:40 Tommy Liang 阅读(225) | 评论 (0)编辑 收藏

仅列出标题
共6页: 1 2 3 4 5 6