Note of Justin

关于工作和读书的笔记

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  47 Posts :: 0 Stories :: 45 Comments :: 0 Trackbacks

留言簿(14)

搜索

  •  

积分与排名

  • 积分 - 51778
  • 排名 - 433

最新评论

阅读排行榜

评论排行榜

[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-05-11


看到题目我笑了,原来traits也被大师归为55式不外传神功之一。看来当初花的时间还是值得的啊@#¥%

貌似谈到traits都要扯上STL、Boost,大师这回也未能免俗。开课就先介绍5种迭代器,input_iterator, output_iterator, forward_interator, bidirectional_iterator 和random_access_iterator。不过我不想再走老路了,还是自己杜撰些东东来比较好玩。

大师说:traits首先应该是个结构体(struct),然后是个被当作类来用的结构体,因为用了公有继承来表示以上5种迭代器的关系(@#$%)
Traits 也叫“Baggage Class”(Nathan C. Myers, C++ Report, June 1995)。在我看来,traits可以理解为类型信息榨取机,制造它的过程大致分以下几步,这里来个简单的例子,我们以不同食物的好吃/不好吃作为食物的类型:

1、既然和类型信息有关,首先需要知道所有可能的类型(如果是void,int之类的已经类型,就可以忽略此步骤),我们的食物有一下两种类型:
struct yummy {};
struct yucky {};

2、用一个模板化的traits结构体来构造用于榨取类型信息的“吸管”:
template <typename T>
struct food_traits
{
    typedef typename T::Taste taste;
};

上面的“吸管”用来得到某种食物的好吃/不好吃属性。“吸管”能工作的前提是:某食物类一定要有这一属性,要么好吃(yummy)要么不好吃(yucky)。

3、然后根据不同的食物制定不同的模板函数的重载:
template <typename T>
string doTry ()
{
    
return "well, i don't know what this is but i will till take a try..";
}

template 
<typename T>
string doTry(T&, yummy)
{
    
return "of course i like this!";
}

template 
<typename T>
string doTry (T&, yucky)
{
    
return "no,keep it away from me..";
}

4、当然,每个“食物”在制作的过程中也要加入好吃/不好吃的元素:
class Cheeseburg
{
    
public:
        typedef yummy Taste;
    
//..
};

class Wasabi
{
    
public:
        typedef yucky Taste;
    
//..
};

5、最后……当然就是品尝食物咯~~
int main()
{
    Cheeseburg C;
    Wasabi W;

    cout 
<< "Cheeseburg? :" << doTry(C, food_traits<Cheeseburg>::taste()) << endl;
    cout 
<< "Wasabi?         :" << doTry(W, food_traits<Wasabi>::taste()) << endl;

    
return 0;
}

这个例子比较STL或是其他的真实例程来说比较简单明了,而且有我爱吃的芝士堡,希望你也喜欢:)

不过在大师的课堂里,其实还有一步。为了使调用第3步中的重载模板函数更简单,隐藏不必要的细节,我们可以再加上一层wrapper函数:
template <typename T>
string Try(T& food)
{
    
return doTry(food, typename food_traits<T>::taste());
}

然后上面的调用就简化为:
//..
cout << "Cheeseburg? :" << Try(W) << endl;
cout 
<< "Wasabi?         :" << Try(C) << endl;
//..

posted on 2010-05-12 10:35 Justin.H 阅读(1851) 评论(6)  编辑 收藏 引用 所属分类: Effective C++ 炒冷饭

Feedback

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 11:59 陈梓瀚(vczh)
应该是Try<Wasabi>();  回复  更多评论
  

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 12:25 Justin.H
@陈梓瀚(vczh) 哦?可以解释一下为什么吗?  回复  更多评论
  

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 19:34 陈梓瀚(vczh)
@Justin.H
因为你仅仅是需要得到那个类型,而不是得到那个类型的行为,所以不需要创建wasani的实例。因此Try也就不能要求用户传入一个实例了。因此直接传入类型。  回复  更多评论
  

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 20:20 陈昱(CY)
还是模板特化比函数容易想到~~

#include<iostream>
#include<string>
using namespace std;

struct Gooood{};
struct Baaaad{};

template<typename T>
class TasteFood
{
public:
static void Test()
{
cout<<"er...I don't know this smell,taste fail........"<<endl;
}
};

template<>
class TasteFood<Gooood>
{
public:
static void Test()
{
cout<<"this food tasted goooooooooood~~~~~"<<endl;
}
};

template<>
class TasteFood<Baaaad>
{
public:
static void Test()
{
cout<<"this food tasted baaaaaaad........."<<endl;
}
};

class Pizzzzzza
{
public:
typedef Gooood T_Tasted;
};
class FoodInSchool
{
public:
typedef Baaaad T_Tasted;
};

template<typename T>
void AfterEat(T&food)
{
TasteFood<typename T::T_Tasted>::Test();
}


int main()
{
Pizzzzzza food1;
FoodInSchool food2;

AfterEat(food1);
AfterEat(food2);

int a;
cin>>a;
return 0;
}  回复  更多评论
  

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 20:28 陈昱(CY)
不过感觉仍然有不足,两个食物里面都要定义一个typedef  回复  更多评论
  

# re: 读书笔记:Effective C++ 炒冷饭 - Item47 traits:类型信息榨取机 2010-05-12 21:31 Justin.H
@陈梓瀚(vczh)
嗯,有道理。受教了。  回复  更多评论
  


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