我有一个以下示例(具有过度安全的布尔类型):
#include <cstdlib>
struct boolean_type
{
explicit
boolean_type(bool _value)
: value_(_value)
{ ; }
explicit
operator bool () const
{
return value_;
}
private :
bool value_;
};
struct A
{
A(int const _i)
: i_(_i)
{ ; }
boolean_type operator == (A const & _other) const
{
return (i_ == _other.i_);
}
private :
int i_;
};
bool t()
{
return A(0) == A(0);
}
int main()
{
return EXIT_SUCCESS;
}
众所周知,这样的代码包含错误:“无法转换”(((int)((const A *)this) - &gt; A :: i_)==((int) other.A :: i ))'从'bool'到'boolean_type'“在bool A::operator == (A const &) const
的return语句中”并且“无法在{{1的返回语句中将'boolean_type'转换为'bool'” }}。但这里有什么风险?为什么在这两种情况下都没有明确的转换?为什么隐含?事实上,我们在第二种情况下明确指定了返回类型bool t()
,并且bool
就是这样!
另外想说:
由于指定的障碍,我无法在我的用户代码中将static_assert(std::is_same< bool, decltype(std::declval< int >() == std::declval< int >()) >::value, "!");
的所有条目替换为我的超级安全bool
( mocked-object ),因为,例如,在boolean_type
使用上述结构的回报语句中,将那里视为隐式转换。类似的障碍并不是唯一的。
答案 0 :(得分:3)
您有两个隐式转换。一个在这里:
return (i_ == _other.i_);
另一个在这里:
return A(0) == A(0);
这些是隐式的,因为您没有明确告诉编译器您希望将比较结果分别转换为boolean_type
和bool
。不允许进行这些隐式转换,因为您同时创建了boolean_type
explicit
的构造函数和转换运算符 - 这就是explicit
关键字的整个点。
您需要这样做:
return static_cast<boolean_type>(i_ == _other.i_);
和
return static_cast<bool>(A(0) == A(0));
明确转换为bool
的典型原因是因为转换可能会在您不打算使用它的情况下使用。例如,如果您有boolean_type
个名为b1
的对象和b2
次转化为非explicit
的对象,则可以执行以下操作:
b1 > 0
b1 == b2
这些可能不是布尔转换运算符的预期用途。
答案 1 :(得分:0)
为什么在这两种情况下都没有明确的转换?
因为on 你,程序员,如果你想要一个明确的转换,那就明确了。
如果您允许,隐式转换在这种情况下会起作用。但是,当您将operator bool
和boolean_type::boolean_type
标记为explicit
时,您不允许这样做。
为什么隐含?
因为你没有写转换。你必须:
boolean_type operator == (A const & _other) const
{
return boolean_type (i_ == _other.i_);
}
...和
bool t()
{
return (bool) (A(0) == A(0));
}
你告诉我们。但这里有什么风险?
explicit
专门用于告诉编译器可能存在允许进行某些隐式转换的风险。因此,当您将这些函数标记为explicit
时,您对编译器说:
好的,如果允许从bool到a的隐式转换 boolean_operator,反之亦然,可能会发生一些不好的事情。所以不要 允许那些隐式转换。
您没有告诉编译器(或我们)为什么这些隐式转换是危险的。你只是说他们是。