「More C++ Idioms/安全な bool(Safe bool)」の版間の差分

削除された内容 追加された内容
Yak! (トーク | 投稿記録)
 
Yak! (トーク | 投稿記録)
en:More C++ Idioms/Safe bool (15:52, 27 October 2007 UTC) から (18:27, 28 May 2008 UTC) への変更を翻訳して反映。
1 行
=<center>安全な bool(Safe bool)</center>=
== 意図 ==
=== 意図 ===
あるクラスに、望まない式評価に含まれないよう制限した上で真偽値としてのテストを提供する。
 
=== 別名 ===
 
=== 動機 ===
ユーザー定義の真偽値への変換関数は利益よりも害をもたらしうる。なぜなら、それにより理想的には含まれて欲しくない式評価に、そのクラスが含まれることを許すからである。単純な変換演算子が定義されている場合、2つあるいはそれ以上の無関係なオブジェクトが比較可能になってしまい、型安全性が損なわれる。
例えば
<source lang="cpp">
classstruct Testable
{
operator bool() const {
return ok_false;
}
};
classstruct AnotherTestable
{
operator bool() const {
return ok_true;
}
};
int main (void)
{
Testable a;
AnotherTestable b;
if (a == b) { /* blah blah blah*/ }
if (a < 0) { /* blah blah blah*/ }
// 上の比較は偶発的なものであり意図したものではないが、コンパイラは喜んでコンパイルする。
return 0;
}
Testable a;
AnotherTestable b;
if (a == b) { /* …… */ }
// 上の比較は事故で意図したものではない
</source>
=== 解法とサンプルコード ===
安全な bool(Safe bool)イディオムは、直感的な if 文を使ったテストという構文的な利便性を可能とするが、同時に、知らぬ間にコンパイルされてしまう意図しない文を防ぐ。
以下が、安全な bool(Safe bool)イディオムのコードである。
<source lang="cpp">
40 ⟶ 47行目:
}
};
class AnotherTestable ... // Testable と同一。
{};
int main (void)
{
Testable t1;
AnotherTestable t2;
if (t1) {} // 期待通りに動く
if (t2 == t1) {} // コンパイルに失敗する
if (t1 < 0) {} // コンパイルに失敗する
 
return 0;
}
</source>
 
47 ⟶ 66行目:
<source lang="cpp">
class safe_bool_base {
public:
protected:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
protected:
 
safe_bool_base() {}
57 ⟶ 77行目:
};
 
// 仮想関数なしでのテスト性のため
template <typename T=void> class safe_bool : public safe_bool_base {
template <typename T=void>
class safe_bool : private safe_bool_base {
// main 中でアクセス制御違反を引き起こすために、
// private 継承か、protected 継承であることが非常に重要
public:
operator bool_type() const {
67 ⟶ 91行目:
};
 
 
template<> class safe_bool<void> : public safe_bool_base {
// 仮想関数ありでのテスト性のため
template<>
class safe_bool<void> : private safe_bool_base {
// main 中でアクセス制御違反を引き起こすために、
// private 継承か、protected 継承であることが非常に重要
public:
operator bool_type() const {
return boolean_test()==true ?
? &safe_bool_base::this_type_does_not_support_comparisons : 0;
safe_bool_base::this_type_does_not_support_comparisons();
}
protected:
77 ⟶ 108行目:
virtual ~safe_bool() {}
};
 
template <typename T>
bool operator==(const safe_bool<T>& lhs, bool b) {
if (b)
{
if (lhs) return true;
else return false;
}
else
{
if (lhs) return false;
else return true;
}
}
 
template <typename T>
bool operator==(bool b, const safe_bool<T>& rhs) {
if (b)
{
if (rhs) return true;
else return false;
}
else
{
if (rhs) return false;
else return true;
}
}
 
 
template <typename T, typename U>
void operator==(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
lhs.this_type_does_not_support_comparisons();
return false;
}
 
87 ⟶ 146行目:
void operator!=(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
lhs.this_type_does_not_support_comparisons();
return false;
}
</source>
どのように safe_bool を用いるかを以下に示す。
<source lang="cpp">
#include <iostream>
 
class Testable_with_virtual : public safe_bool<> {
public:
virtual ~Testable_with_virtual () {}
protected:
virtual bool boolean_test() const {
// 真偽値に変化するロジックをここで実行
return true;
}
};
 
class Testable_without_virtual :
public safe_bool <Testable_without_virtual> {// CRTP イディオム
{
public:
/* 「非」仮想 */ bool boolean_test() const {
// 真偽値に変化するロジックをここで実行
return false;
}
};
 
int main (void)
{
Testable_with_virtual t1, t2;
Testable_without_virtual p1, p2;
if (t1) {}
if (p1 == false)
{
std::cout << "p1 == false\n";
}
if (p1 == p2) {} // 期待通り、コンパイルできない
if (t1 != t2) {} // 期待通り、コンパイルできない
 
return 0;
}
</source>
C++ では、派生クラスでは protected なメンバ関数のアドレスを取ることはできない。
派生クラスは通常のクラス、クラステンプレート、クラステンプレートの特殊化になりうる。
安全な bool(Safe bool)イディオムの実装には safe_bool_base::this_type_does_not_support_comparisons を派生クラスでそのアドレスを取ることができないように protected として宣言するものがある。
再利用可能な安全な bool(Safe bool)イディオムの要求である。
不幸にも、g++ コンパイラには、protected として宣言されているとしてもクラステンプレートで safe_bool_base::this_type_does_not_support_comparisons のアドレスが取れてしまうというアクセス制御の[http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33934 バグ]が存在する。
 
=== 既知の利用 ===
* boost::scoped_ptr
* boost::shared_ptr
* boost::optional
 
=== 関連するイディオム ===
 
=== References ===
http://www.artima.com/cppsource/safebool.html
 
<noinclude>
[[en:More C++ Idioms/Safe bool]]
</noinclude>
[[Category:{{BASEPAGENAME}}|{{SUBPAGENAME}}]]
[[Category:{{BASEPAGENAME}}|あんせんなBOOL]]