const 正确性和安全 bool 习惯用法
我还有另一个与安全 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
(typedef)和 this_type_does_not_support_comparisons
是 const
? 无论如何,没有人应该通过返回指针实际调用成员函数,对吗? 这里需要const吗?否则operator bool_type
(成员函数)会违反常量正确性吗?
I have another question related to the safe bool idiom:
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;
}
How come the bool_type
(the typedef) and this_type_does_not_support_comparisons
are const
?
Nobody is supposed to actually call the member function through the return pointer anyway, right?
Is const
necessary here? Would operator bool_type
(the member function) violate const-correctness otherwise?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
“safe bool idiom”是对“我想要一辆既是跑车又是拖拉机,也许是船”这个问题的技术答案。实际答案不是技术答案……
也就是说,它解决的问题只是给出一个可转换为 bool 的结果,但不能转换为任何其他内容(否则该类的实例可能会作为实际参数传递,例如,形式参数是
int
)。数据指针可以转换为void*
。函数指针不是,至少在 C++ 标准中是这样(Posix 是别的东西,也可以练习)。给定来自安全布尔运算符的指针,使用成员函数指针可以防止意外调用该函数。
const 对其进行了一些限制,但如果命运使某人走上了犯最大数量愚蠢错误的道路,那么该人仍然可能设法调用不执行任何操作的函数。我想我应该让它有一个私有类型的参数,而不是 const ,而其他代码不能提供这样的参数,然后它就不必是一个愚蠢的不再是成员函数类型了。可以看起来像这样:
当然,实际的答案是这样的:
Summary wrt。提出的问题:
有人不太明白他们编码的内容。或者也许他们打算稍微限制一下打电话的能力。但这样的措施是徒劳的。
正确的。
否。否则,
不。
干杯&呵呵,
The "safe bool idiom" is the technical answer to the question "i want a vehicle that is both sports car and tractor, and maybe a boat". The practical answer is not the technical answer…
That said, the problem it solves is just to give a result that is convertible to
bool
but not to much of anything else (otherwise an instance of the class could be passed as actual argument where e.g. the formal argument wasint
, say). A data pointer could be convertible tovoid*
. A function pointer isn't, at least formally within the C++ standard (Posix is something else, practice also).Using a member function pointer protects against accidentally calling the function, given the pointer from the safe bool operator.
TheI think I would just let it have an argument of a private type, where other code cannot provide such an argument, and then it doesn't have to be a silly member function type anymore.const
constricts it a bit, but if fate has put someone on the path of making maximum number of silly mistakes, that person might still manage to call the do-nothing function. Instead of theconst
Can look like this:
Of course, the practical answer is instead something like this:
Summary wrt. questions asked:
Somebody didn't quite understand what they coded. Or maybe they intended to restrict the ability to call, a little. But then, pretty futile measure.
Right.
No.
No.
Cheers & hth.,
如果我没看错,您可以在 const 成员函数中返回指向非 const 成员的指针。您只是无法使用非常量对象来调用它。
禁止调用的一种方法是:
仍然可以比较指向成员函数的指针是否相等。您必须为触发错误的
Testable::bool_type
类型编写operator==
和operator!=
。使用安全 bool 习惯用法的 CRTP 形式更容易实现,因为这些运算符成为模板,因此可能具有错误的主体。示例:
那么你可以这样做(与
!=
做同样的事情):这意味着如果你想禁止比较,应该通过 CRTP 实现 safe bool 习惯用法。然而与零的比较仍然有效。
如果您采用非成员函数路线,则必须提供
<
、>
、<=
和>=
也是如此。If I read correctly, you can return a pointer to non const member in a const member function. You just won't be able to call it with a non const object.
A way to forbid the calling is:
Pointer to member functions can still be compared for equality. You have to write an
operator==
andoperator!=
forTestable::bool_type
types which trigger an error. Easier to do with the CRTP form of the safe bool idiom since those operators become templates and thus can have an erroneous body.Example:
then you can do (do the same with
!=
):This means that the safe bool idiom should be implemented via CRTP if you want to forbid comparisons. Comparisons to zero will still work however.
If you go the non-member function route, you'll have to provide
<
,>
,<=
and>=
too.虽然这很旧,但安全 bool 习语有其历史意义,我决定写一个完整的答案,因为我真的不同意 接受的答案< /a>.
重要的是我们不能孤立地回答这个问题。该函数被称为
this_type_does_not_support_comparisons
是有原因的。它不仅仅是一些随机的私人成员。意图很明确:该函数还用于避免两个测试对象之间的意外比较。例如,如果我们查看此处的实现,我们可以看到该函数实际上被调用了。首先请注意,此代码无法在现代编译器上编译,因为无论
T
是什么,函数体都无条件地格式错误。不过,让我们从历史的角度来考虑一下。在较旧的 C++ 中这确保了在两个可测试对象上调用
operator==
时,比较消息可以很好地指示真正的问题。例如,GCC 4.1.2 生成以下错误消息。这就是为什么首先调用该函数
this_type_does_not_support_comparison
的原因。const
需要在那里,因为该函数实际上是在需要const
的上下文中调用的,即templatebool 运算符==(const Testable&lhs, const T&)
。请注意,不能从第一个参数中删除 const,否则它无法检测 const 对象与另一个对象之间的比较,并且再次可以静默转换为 bool。以下是我对以下问题的回答:
bool_type
(typedef)和this_type_does_not_support_comparisons
是 const?因为该函数实际上被调用,并且 const 对于抑制在operator== 上下文中隐式转换为 bool 是必要的。这绝对不是因为有人不理解他们写的内容,也不是为了阻止使用
(testable.*testable)()
语法调用可测试对象(这已经是一种非常奇特的用法,没有人使用bool 之类的,所以这根本不应该被认为是要防止的意外误用,而且,如果你尝试它,它实际上不会编译)。大部分是对的。成员函数不应该从外部调用,但实际上是在类本身的比较运算符中调用的。很容易错过这个用法,因为它没有包含在问题的原始片段中。
再说一次,如果我们将自己限制在发布的代码片段中,则不会;如果我们考虑如何实现规范的 safe bool 习惯用法的更广泛的背景,那么是的。
operator bool_type
(成员函数)会违反常量正确性吗?如果我们只考虑发布的片段,则不会。是的,在更广泛的背景下。在 Alexandre C.的回答中,已经解决了为什么在 const 中返回指向非 const 成员的指针-限定成员函数不违反常量正确性。
当然,现在是 2023 年,如果有人拥有支持 c++11 的现代编译器,他们应该只使用显式运算符 bool() 并忘记所有这些。然而,可能仍然有一些可怜的人需要使用仅限于 c++03 的遗留环境,在这种情况下,可能的答案是 Alexandre C. 提供了一个可能更好的选择。毕竟,即使标准设置为 c++03,原始版本的 safe bool idiom 也无法使用新编译器进行编译。
Although this is old, the safe bool idiom has its historical significance and I decide to write a full answer because I really disagree with the accepted answer.
One important thing is that we cannot answer this question in isolation. The function is called
this_type_does_not_support_comparisons
for a reason. It is not just some random private member. The intention is clear: the function is also used to avoid accidental comparison between two testables. If for example we look at the implementation here, we can see that the function is actually called.Note first that this code will not compile on modern compilers because the body of the function is unconditionally ill-formed no matter what
T
is. However, let's consider it from a historical perspective. In older c++versions this ensures that when
operator==
is called on two testables, and the comparison message nicely indicates the real issue. For example, GCC 4.1.2 generates the following error message.This is why the function is called
this_type_does_not_support_comparison
in the first place. Theconst
need to be there because the function is actually called in a context whereconst
needed, namelytemplate <typename T> bool operator==(const Testable& lhs, const T&)
. Note thatconst
cannot be removed from the first parameter because otherwise it cannot detect the comparison between a const object and another object and silent conversion tobool
becomes possible again.So here are my answers to the questions,
bool_type
(the typedef) andthis_type_does_not_support_comparisons
are const?Because the function is actually called and the
const
s are necessary to suppress the implicit conversion to bool in the context ofoperator==
. It's definitely not because someone did not understand what they wrote or to prevent the testables to be called with the(testable.*testable)()
syntax (That is already a very exotic use and no one uses a bool like that, so that should not be considered an accidental misuse to be prevented at all. Moreover, if you try it, it doesn't actually compile).Mostly right. The member functions are not supposed to be called from outside but are actually called in the comparison operators from the class itself. It is easy to miss this use because it is not included in the original snippet of the question.
Again, no if we limit ourselves to the snippet posted, yes if we consider the broader context of how the canonical safe bool idiom is implemented.
operator bool_type
(the member function) violate const-correctness otherwise?No if we just consider the snippet posted. Yes in the broader context. In the answer by Alexandre C. it is already addressed why returning a pointer-to-non-const-member in a const-qualified member function does not violate the const-correctness.
Of course, it is 2023 now and if anyone has a modern compiler that supports c++11 they should just use
explicit operator bool()
and forget all these. However, there may still be poor guys who need to work with legacy environment restricted to c++03, and in that case maybe the answer by Alexandre C. provides a possibly better alternative. After all, the original version of safe bool idiom does not compile with new compilers even if the standard is set to c++03.