关于safe bool idiom

hityct1 2009-03-03 12:14:24
看了一点boost,里面提到safe bool idiom,现在已经知道使用它的原因。但是原理不明白。具体问题在代码的注释中。

#include <iostream>

//using namespace std;

//safe bool idiom示例
class Testable {
bool ok_;
public://加了个它
typedef void (Testable::*bool_type)();// const;//去掉原来的全部const,不影响输出
void this_type_does_not_support_comparisons() //const //去掉原来的全部const
{}
public:
explicit Testable(bool b=true):ok_(b) {}

//safe bool idiom
operator bool_type() //const //去掉原来的全部const
{
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};

//对比1
typedef void (*bool_type2)();
void this_type_does_not_support_comparisons2()
{
}
class Testable2 {
bool ok_;
public:

public:
explicit Testable2(bool b=true):ok_(b) {}

operator bool_type2()
{
return ok_==true ?
&this_type_does_not_support_comparisons2 : 0;
}
};

//对比2
typedef void (*PFUN)();
void comparisons()
{
}

int main()
{
Testable tt(true);
std::cout<< tt <<std::endl;//输出1。为什么tt被当成bool型输出?这个是关键问题。
//std::cout<< tt.operator bool_type() <<std::endl;//附带问题:如何显示调用这个转换操作符?

Testable2 tt2(true);
std::cout<< tt2 <<std::endl;//为什么不输出1?与Testable的区别何在?
std::cout<< tt2.operator bool_type2() <<std::endl;

std::cout << ( true?&comparisons:0 ) << std::endl;//为什么不输出1?
std::cout << reinterpret_cast<PFUN>( true?&comparisons:0 ) << std::endl;//为什么不输出1?
std::cout << static_cast<PFUN>( true?&comparisons:0 ) << std::endl;//为什么不输出1?

return 0;
}
...全文
363 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
hityct1 2009-03-04
  • 打赏
  • 举报
回复
9楼引经据典,看来有两个条:
1)a pointer to member cannot be converted to a void*.
2)An rvalue of pointer to member type can be converted to an rvalue of type bool.
hityct1 2009-03-03
  • 打赏
  • 举报
回复
甘草似乎没有回到我的问题。
hityct1 2009-03-03
  • 打赏
  • 举报
回复
我记得好像在哪看到似乎使用的是c++的一个缺陷/漏洞,但找不到了。
healer_kx 2009-03-03
  • 打赏
  • 举报
回复
最后就是一段代码,说明为什么成员函数的可以,非成员函数的不可以,也是由于这种技巧依赖于类型直接的转化。

void* a = Testable::this_type_does_not_support_comparisons;
void* b = this_type_does_not_support_comparisons2;
实际你会发现,第一行的是编译不过的,尽管也是个指针。
  • 打赏
  • 举报
回复
mark先
healer_kx 2009-03-03
  • 打赏
  • 举报
回复
http://visnuhoshimi.spaces.live.com/blog/cns!35416b2a4dc1b31b!2040.entry
healer_kx 2009-03-03
  • 打赏
  • 举报
回复
http://hi.baidu.com/shilei4223/blog/item/10c499589b88e482800a18e5.html
healer_kx 2009-03-03
  • 打赏
  • 举报
回复
这种手法的关键的目的是为了防止bool类型会(轻易地)转化为int,long等类型。
但是采用某种指针类型就不会了,技巧在于指针类型,0可以是指针类型的有效值,而一个bool值,或者整数值,不可以。
boost里面还是用了一些这种技巧的。
太乙 2009-03-03
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hityct1 的回复:]
甘草似乎没有回到我的问题。
[/Quote]

感觉回答的挺好啊~~
nineforever 2009-03-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 nineforever 的回复:]
cout有两个重载bool和void *,普通指针可以转换为void *,所以会调用后面那个重载输出地址。成员函数指针不能转换成void *,所以会调用前面那个重载,输出1。
[/Quote]

严格而言,根据标准普通函数指针是不能隐式转换成void *的,而能否显式转换取决于编译器。VC支持隐式转换,所以才会出现选择void *版本的情况
gcc总会使用bool的版本
baihacker 2009-03-03
  • 打赏
  • 举报
回复
In particular, a pointer to member cannot be converted to a void*.
baihacker 2009-03-03
  • 打赏
  • 举报
回复
4.11 Pointer to member conversions [conv.mem]
1 A null pointer constant (4.10) can be converted to a pointer to member type; the result is the null member
pointer value of that type and is distinguishable from any pointer to member not created from a null pointer
constant. Two null member pointer values of the same type shall compare equal. The conversion of a null
pointer constant to a pointer to member of cv-qualified type is a single conversion, and not the sequence of
a pointer to member conversion followed by a qualification conversion (4.4).
2 An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an
rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an
inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this
conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member
before the conversion took place, but it refers to the base class member as if it were a member of the
derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to
member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to
member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to
the null member pointer value of the destination type.52)
4.12 Boolean conversions [conv.bool]
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of
type bool. A zero value, null pointer value, or null member pointer value is converted to false; any
other value is converted to true.
__________________
52) The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted
compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to
ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of
such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.
63
nineforever 2009-03-03
  • 打赏
  • 举报
回复
cout有两个重载bool和void *,普通指针可以转换为void *,所以会调用后面那个重载输出地址。成员函数指针不能转换成void *,所以会调用前面那个重载,输出1。

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧