【问题标题】:C++11 explicit conversion operators/constructors in return statementreturn 语句中的 C++11 显式转换运算符/构造函数
【发布时间】:2014-02-04 08:15:05
【问题描述】:

我有以下示例(使用过于安全的布尔类型):

#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;
}

众所周知,这样的代码包含错误:“could not convert '(((int)((const A*)this)->A::i_) == ((int)other .A::i))' 在bool A::operator == (A const &amp;) const 的返回语句中从 'bool' 到 'boolean_type' 和在 bool t() 的返回语句中“无法将 'boolean_type' 转换为 'bool'”。但这里有什么风险?为什么在这两种情况下都没有显式转换?为什么是隐式的?事实上,我们在第二种情况下明确指定了返回类型 boolstatic_assert(std::is_same&lt; bool, decltype(std::declval&lt; int &gt;() == std::declval&lt; int &gt;()) &gt;::value, "!"); 一样!

另外想说:

由于指定的障碍,我不能简单地将bool 的所有条目替换为我的用户代码中的超级安全boolean_type(即 mocked-object),因为,比如说,在boost::variant::operator == 的返回语句中使用上述构造,将那里视为隐式转换。类似的障碍不是唯一的。

【问题讨论】:

  • Q中根本没有重复,因为讨论中隐含着对重要细节的考虑。
  • 这段代码是从哪里来的?
  • 委员会对这个问题进行了很多辩论(应该返回意味着显式转换为返回类型)...
  • @Dukales 我记得那些不是公开对话。但您可以搜索 wg21 问题列表和 isocpp.org 邮件列表。
  • @JohnDibling return 是一个非常特殊的情况。您已经拼出了要转换为上面几行的类型。这与转换为函数中从未提及的某些随机类型不同。然后它变成了一个品味问题。我认为必须在每个 return 语句中重复类型是一种痛苦。

标签: c++ c++11 type-conversion implicit-conversion


【解决方案1】:

为什么在这两种情况下都没有显式转换?

因为如果您想要显式转换,那么程序员有责任明确说明。

如果您允许隐式转换,则在这种情况下会起作用。但是当您将 operator boolboolean_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 隐式转换为 boolean_operator 或反之亦然,可能会发生不好的事情。所以不要 允许那些隐式转换。

你没有告诉编译器(或我们)为什么这些隐式转换是危险的。你只是说他们

【讨论】:

  • @Dukales:当然,好的。我可能会想出一些人为的例子,其中隐式转换要么正是你想要的,要么不是你想要的,但这不是重点。关键是您告诉编译器不允许这些隐式转换,然后尝试使用一个。因此,就编译器而言,那里的风险是,如果它允许那些隐式转换,那么它就会做一些你告诉它不要做的事情。
  • 目前这种explicit 转换构造函数/转换运算符几乎没用。见Q中的补充。
【解决方案2】:

您有两个隐式转换。一个在这里:

return (i_ == _other.i_);

这里还有一个:

return A(0) == A(0);

这些是隐含的,因为您没有明确告诉编译器要将比较结果分别转换为boolean_typebool。不允许这些隐式转换,因为您同时创建了 boolean_type explicit 的构造函数和转换运算符 - 这就是 explicit 关键字的全部意义。

你需要这样做:

return static_cast<boolean_type>(i_ == _other.i_);

还有:

return static_cast<bool>(A(0) == A(0));

显式转换为bool 的典型原因是,转换可能用于您不打算使用它的情况。例如,如果您有名为 b1b2boolean_type 对象具有非explicit 转换,则可以执行以下操作:

b1 > 0
b1 == b2

这些可能不是布尔转换运算符的预期用途。

【讨论】:

  • 但是风险呢?
  • @Dukales 风险在于您从未打算将bools 隐式转换为boolean_type,反之亦然。如果这不是风险,你不应该让他们explicit。通过将它们设为explicit,是您声明存在风险。
  • 我在这里看到了明显的风险:boolean_type(false) + boolean_type(true);,但在上面的例子中没有。
  • 有人可能会争辩说,指定函数的返回类型已经是一种非常明确的方式来说明您想要返回什么类型。
  • @JohnDibling 让我们同意不同意。我通过指定函数的返回类型来请求转换。试图保姆我并通过重复多次来强迫我使用婴儿语的标准只是一种痛苦。
猜你喜欢
  • 1970-01-01
  • 2011-04-24
  • 2015-11-28
  • 2016-10-13
  • 1970-01-01
  • 2012-04-16
  • 2017-12-21
  • 2021-12-03
相关资源
最近更新 更多