我还有一个关于安全bool习惯用法的问题:
typedef void (Testable::*bool_type)() const; // const necessary?
void this_type_does_not_support_comparisons() const {} // const necessary?
operator bool_type() const
{
return ok_ ? &Testable::this_type_does_not_support_comparisons : 0;
}
为什么bool_type
(类型定义)和this_type_does_not_support_comparisons
是const
?实际上没有人应该通过返回指针调用成员函数,对吧?这里需要const
吗?否则operator bool_type
(成员函数)会违反常量正确性吗?
"安全bool习语"是对这个问题的技术回答:"我想要一辆既是跑车又是拖拉机的车,也许还有一艘船"。实用的答案不是技术的答案& help;
也就是说,它解决的问题只是给出一个可转换为bool
的结果,而不是其他任何东西(否则类的实例可以作为实际参数传递,例如,形式参数是int
)。数据指针可以转换为void*
。函数指针不是,至少在c++标准中是正式的(Posix是另一回事,也要实践)。
使用成员函数指针可以防止意外调用该函数,因为指针来自安全bool操作符。
const
对它有一些限制,但如果命运让某人犯了最多的愚蠢错误,那个人可能仍然会设法调用什么都不做的函数。而不是const
可以像这样:
#include <stdio.h>
class Foo
{
private:
enum PrivateArg {};
typedef void (*SafeBool)( PrivateArg );
static void safeTrue( PrivateArg ) {}
bool state_;
public:
Foo( bool state ): state_( state ) {}
operator SafeBool () const
{ return (state_? &safeTrue : 0); }
};
int main()
{
if( Foo( true ) ) { printf( "truen" ); }
if( Foo( false ) ) { printf( "falsen" ); } // No output.
//int const x1 = Foo( false ); // No compilado!
//void* const x2 = Foo( false ); // No compilado!
}
当然,实际的答案是这样的:
#include <stdio.h>
class Foo
{
private:
bool isEmpty_;
public:
Foo( bool asInitiallyEmpty )
: isEmpty_( asInitiallyEmpty )
{}
bool isEmpty() const { return isEmpty_; }
};
int main()
{
if( Foo( true ).isEmpty() ) { printf( "truen" ); }
if( Foo( false ).isEmpty() ) { printf( "falsen" ); } // No output.
//bool const x0 = Foo( false ); // No compilado!
//int const x1 = Foo( false ); // No compilado!
//void* const x2 = Foo( false ); // No compilado!
}
关于总结。提问:
- 为什么bool_type (typedef)和this_type_does_not_support_comparison是const?
有人不太明白他们写了什么。或者也许他们想要限制调用的能力。但是,这是相当无用的措施。
- 没有人应该通过返回指针调用成员函数,对吧?
.
- 这里const是必需的吗?
- operator bool_type(成员函数)是否违反const-正确性?
干杯,hth。
8.3.5/A cv-qualifier-seq只能是for的函数类型的一部分非静态成员函数,指针指向的函数类型成员引用,或函数typedef的顶级函数类型声明。函数声明符中cv-qualifier-seq的效果是不是和在功能上面加上cv-qualification不一样类型,也就是说,它不创建一个cv限定的函数类型。
如果我没看错的话,可以在const成员函数中返回指向非const成员的指针。只是不能用非const对象调用它。
禁止调用的一种方法是:
private:
struct private_
{
void this_type_does_not_support_comparisons() {}
};
public:
typedef void (private_::*bool_type)() const;
operator bool_type() const
{
return ok_ ? &private_::this_type_does_not_support_comparisons : 0;
}
指向成员函数的指针仍然可以比较是否相等。您必须为触发错误的Testable::bool_type
类型编写operator==
和operator!=
。使用安全bool习惯用法的CRTP形式更容易,因为这些操作符成为模板,因此可能具有错误的主体。
的例子:
template <typename T>
class safe_bool_concept
{
// Implementation detail of safe bool
protected:
~safe_bool_concept() {}
public:
operator safe_bool() const
{
return static_cast<const T*>(this)->is_null() ? ...;
}
};
struct Foo : safe_bool_concept<Foo>
{
...
private:
friend class safe_bool_concept<Foo>;
bool is_null() const { ... }
};
那么你可以这样做(对!=
做同样的事情):
template <typename T>
void operator==(const safe_bool_concept<T>& x, const safe_bool_concept<T>&)
{
x.some_private_member(); // invalid, but won't be generated
// unless safe_bool classes are compared
}
这意味着如果您想禁止比较,则应该通过CRTP实现安全bool习惯用法。然而,与零的比较仍然有效。
如果您选择非成员函数路线,您还必须提供<
, >
, <=
和>=
。