随笔 - 31  文章 - 128  trackbacks - 0
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(5)

随笔分类(38)

随笔档案(31)

收藏夹(4)

College

High School

最新随笔

搜索

  •  

积分与排名

  • 积分 - 54311
  • 排名 - 408

最新评论

  • 1. re: [yc]详解link
  • 面试的时候面试官就问过我什么是编译和链接,我说编译就是把代码文件生成目标文件,链接就是把目标文件生成可执行文件,他说不对,又问我什么是动态链接,还问我预编译都做什么处理。。。都在这里找到了答案!!!!
  • --王至乾
  • 2. re: [yc]详解link
  • @刘伟
    我是说博主,不是叫你啊
  • --溪流
  • 3. re: [yc]详解link
  • 谁是石老师,我不是哈@溪流
  • --刘伟
  • 4. re: [yc]详解link
  • 石老师?我是溪流~
  • --溪流
  • 5. re: [yc]详解link
  • 期待楼主下文啊,多谢楼主了
  • --刘伟

阅读排行榜

评论排行榜

看了546@C++@Freecity之后,发觉非常有意思,由此产生一些想法

很多时候写一个类的时候,需要多个模版参数,例如一个遗传算法的算法类,需要一个模版参数来指定交配方式,另一个模版参数来指定子代选择的方式,还要一个参数来指定变异的方式。那么一般来说,这个类会写成:

template<class T                                                //描述问题的一个类
        , class CrossPolicy = AvgCrossPolicy                        //杂交方式
        , class SelectPolicy = DefaultSelectPolicy                //子代选择的方式
        , class VariationPolicy = ReverseVariationPolicy>        //变异方式
class Gene
        : private AvgCrossPolicy
        , private SelectPolicy
        , private VariationPolicy
{
        ....
};

这样用户要使用该类的时候,可以直接指定T,就行了,然而如果要指定变异方式,那么就必须把所有的参数都显式的写出来,很不方便

546提供了一种有效的方法,可以让我们仅仅指定变异参数,而不用写出另两个Policy
甚至允许我们以任意的顺序书写几个Policy参数,都不会有问题

预备知识:
TypeList
一个TypeList是一个类型的容器
template <typename Type_, typename Next_>
struct TypeList
{
        typedef Type_ Type;
        typedef Next_ Next;
};
这就是一个TypeList。
看这个写法,是不是像一个链表?
首先定义一个类型来表示链表尾:class NullType{};
现在一个包含了2个类型的TypeList就可以写为:
TypeList<T1, TypeList<T2, NullType>  >

如何在一个TypeList中查找一个类型的子类?
首先要有一个IsDerivedFrom<Base, T>
这个比较简单
template<class Base, class T>
class IsDerivedFrom
{
        struct large{char a[2];};
        static char pred(Base*);
        static large pred(...);
public:
        enum {Is = sizeof(pred((T*)0)) == sizeof(char)};
};

然后FindChild就容易了
template <class List, class Base>
struct FindChild
{
        template <bool IsChild>
        struct Select
        {
                typedef typename List::Type Type;
        };

        template <>
        struct Select<false>
        {
                typedef typename FindChild<typename List::Next, Base>::Type Type;
        };

        typedef typename Select<IsDerivedFrom<Base, typename List::Type> >::Type Type;
};

当然还要对一些特殊情况进行特化,例如NullType
template <class Base>
struct FindChild<NullType, Base>
{
        typedef NullType Type;
};
这里使用NullType来表明没找到

实际操作:
首先需要给3个Policy3个基类,分别叫
class AvgCrossPolicyBase{};
class SelectPolicyBase{};
class VariationPolicyBase{};
内容为空就行了,这样也没有虚函数调用的开销


然后声明一个类来表示默认情况:
class DefaultPolicy{};

定义一个宏
#define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >

下面要写一些选择器,用于把合适的类型选择出来,如果没找到,则要使用默认的类型
template <class List, class Base, class DefaultType>
struct Selector
{
        template <class RetType>
        struct Judge
        {
                typedef RetType Type;
        };
       
        template<>
        struct Judge<NullType>
        {
                typedef DefaultType Type;
        };
        typedef typename Judge<typename FindChild<List, Base>::Type >::Type Type;
};

好啦,现在整个类的声明可以写为

template<class T
        , class CrossPolicy_ = DefaultPolicy
        , class SelectPolicy_ = DefaultPolicy
        , class VariationPolicy_ = DefaultPolicy     //其后的参数用户不可指定
        , class List = TYPELIST_3_N(CrossPolicy_, SelectPolicy_, VariationPolicy_)
        , class CrossPolicy = typename Selector<List, CrossPolicyBase,  AvgCrossPolicy>::Type
        , class SelectPolicy = typename Selector<List,  SelectPolicyBase,  DefaultSelectPolicy>::Type
        , class VariationPolicy = typename Selector<List,  VariationPolicyBase,  ReverseVariationPolicy>::Type
        >
class Gene
        : private CrossPolicy
        , private SelectPolicy
        , private VariationPolicy
{
       
        ....
};


其中第4-7个参数(List,CrossPolicy,SelectPolicy和VariationPolicy)是不由用户指定的,仅仅是为了起一个别名
第一个参数T必须指定,然后2,3,4这3个参数就可以任意的改变顺序了
例如,可以写Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不会有任何问题
如果不想要最后面几个参数的话也行,但是代码就要稍微长一点
而且最好在类里面进行3个typedef
typedef typename Selector<List, CrossPolicyBase,  AvgCrossPolicy>::Type CrossPolicy;
等,以便在实现的时候使用

posted on 2006-07-24 01:06 shifan3 阅读(982) 评论(9)  编辑 收藏 引用 所属分类: templateC++

FeedBack:
# re: 乱序Policy手法 2006-07-24 09:25 小明
华丽是华丽,可是不实在,工程师慎用  回复  更多评论
  
# re: 乱序Policy手法 2006-07-24 12:06 Arcrest
静态的多态还是有用的时候,C++ Modern Design详解
当然项目中的话,维护人员要求高了点。。。

  回复  更多评论
  
# re: 乱序Policy手法 2006-07-24 12:12 Francis Arcanum
这种东西的特点就是,不管怎么搞,也都是编译错误
而编译错误怎么诡异也比运行错误容易解决  回复  更多评论
  
# re: 乱序Policy手法 2006-10-22 08:42 pluskid
T_T
看不懂 C++ 代码~~~
不过,lisp 里面支持乱序参数是使用keyword来支持。例如:
(defun foo (&key foo (bar 'default-bar))
(format t "~A ~A~%" foo bar))

然后可以这样调用:
(foo :bar 'new-bar)
NIL NEW-BAR

or
(foo :bar 'new-bar :foo 'new-foo)
NEW-FOO NEW-BAR

or
(foo :foo 'new-foo)
NEW-FOO DEFAULT-BAR

恩,也许可以参考一下,通过名字来指定是哪个参数。  回复  更多评论
  
# re: 乱序Policy手法 2006-10-22 09:56 Francis Arcanum
通过名字取参数C++有另外一套做法,可以参见boost.parameter
这个可以连名字都不需要,哇哈哈哈哈  回复  更多评论
  
# re: [yc]乱序Policy手法 2007-05-20 07:38 pluskid
寒~~发现原来我以前看过这篇的。不过现在居然能看懂了,看来自己也是有进步的,哈哈~  回复  更多评论
  
# re: [yc]乱序Policy手法[未登录] 2007-08-21 20:17 Jarod
突然发现有个例子是遗传算法,莫非朋友也是搞智能的?  回复  更多评论
  
# re: [yc]乱序Policy手法 2007-08-22 10:27 Francis Arcanum
@Jarod
呵呵,不是,只不过有朋友给我介绍过,觉得这个例子很合适就用上了  回复  更多评论
  
# re: [yc]乱序Policy手法 2009-10-25 12:47 hlysh
看不懂....唉  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理