9

我有另一个与安全布尔成语有关的问题:

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(typedef)和this_type_does_not_support_comparisons是怎么来的const?无论如何,没有人应该通过返回指针实际调用成员函数,对吧?这里有const必要吗?operator bool_type否则(成员函数)会违反 const 正确性吗?

4

2 回答 2

5

“安全布尔成语”是对“我想要一辆既是跑车又是拖拉机,也许还有船”的问题的技术答案。实际答案不是技术答案……

也就是说,它解决的问题只是给出一个可转换为bool但不能转换为其他任何东西的结果(否则,类的实例可以作为实际参数传递,例如,形式参数是int)。数据指针可以转换为void*. 函数指针不是,至少在 C++ 标准中是正式的(Posix 是另一回事,实践也是如此)。

给定来自安全布尔运算符的指针,使用成员函数指针可防止意外调用该函数。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( "true\n" ); }
    if( Foo( false ) ) { printf( "false\n" ); } // 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( "true\n" ); }
    if( Foo( false ).isEmpty() ) { printf( "false\n" ); } // No output.

    //bool const x0 = Foo( false );       // No compilado!
    //int const x1 = Foo( false );        // No compilado!
    //void* const x2 = Foo( false );      // No compilado!
}

总结wrt。问的问题:

  • 为什么 bool_type(typedef)和 this_type_does_not_support_comparisons 是 const?

有人不太明白他们编码的内容。或者他们可能打算稍微限制打电话的能力。但是,相当徒劳的措施。

  • 无论如何,没有人应该通过返回指针实际调用成员函数,对吧?

对。

  • 这里需要 const 吗?

不。

  • 否则 operator bool_type (成员函数)会违反 const 正确性吗?

不。

干杯&hth.,

于 2011-08-11T15:36:13.527 回答
1

8.3.5/ cv-qualifier-seq 只能是非静态成员函数的函数类型、成员指针所指的函数类型或函数 typedef 声明的顶级函数类型的一部分。函数声明器中 cv-qualifier-seq 的效果与在函数类型之上添加 cv-qualification 不同,即它不会创建 cv-qualified 函数类型。

如果我没看错,您可以在 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;
    }

仍然可以比较指向成员函数的指针是否相等。您必须为触发错误的类型编写operator==and 。使用安全布尔惯用语的 CRTP 形式更容易,因为这些运算符成为模板,因此可能具有错误的主体。operator!=Testable::bool_type

例子:

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 实现安全布尔惯用语。然而,与零的比较仍然有效。

如果你走非成员函数路线,你还必须提供<, >,<=等等>=

于 2011-08-11T15:33:16.923 回答