【问题标题】:How to elegantly return an object that is default-initialized?如何优雅地返回默认初始化的对象?
【发布时间】:2013-09-18 21:10:45
【问题描述】:

我有一个像下面这样的课程:

class VeryVeryVeryLongTypeName
{
    bool is_ok;

    VeryVeryVeryLongTypeName() : is_ok(false) {}
};

VeryVeryVeryLongTypeName f()
{
    VeryVeryVeryLongTypeName v;

    ... // Doing something

    if (condition_1 is true)
    {
        return v;
    }
    else
    {
        return VeryVeryVeryLongTypeName();
    }

    ... // Doing something

    if (condition_2 is true)
    {
        return v;
    }
    else
    {
        return VeryVeryVeryLongTypeName();
    }    
}

我觉得return VeryVeryVeryLongTypeName();这个说法很乏味也很丑,所以,我的问题是:

如何优雅地返回默认初始化的对象?

或者换句话说:

在 C++ 标准中添加一项功能以使以下声明合法是个好主意吗?

return default; // instead of return VeryVeryVeryLongTypeName();

【问题讨论】:

  • 为什么你使用一个很长的丑陋的名字让你拒绝使用它? ;-)
  • 长名字不一定难看,只要有意义。仅仅因为“return VeryVeryVeryLongTypeName();”,我觉得它很难看太乏味和没有意义。 “返回 {};”比前者好很多。

标签: c++ c++11 return default-value default-constructor


【解决方案1】:

这更简洁:

   return {};

【讨论】:

  • @JesseGood:看看我的解决方案。
  • 我想在一些代码中使用它,只是为了让我的团队领导 conniptions。这会让我成为一个坏人吗?
  • 我很好奇制作一个没有带默认值的参数的默认构造函数可以解决什么问题?
  • @Troy:请记住,A(int i = 0) 是默认 ctor。答案仍然有效。
  • @Troy:我想我可能误解了你的评论。这是另一个use case
【解决方案2】:

您可以使用此类,其实例将自动隐式转换为 desired 类型的实例。即使默认构造函数被标记为explicit或者如果您仍在使用 C++03,这也应该可以工作。对于 C++11,公认的答案更简洁更好。

const struct default_t
{
     template<typename T>
     operator T() const {   return T{}; }
}default_{};

并将其用作:

VeryVeryVeryLongTypeName f()
{
     //...
     return default_;
}

WithExplicitConstructor_VeryVeryVeryLongTypeName g()
{
     //...
     return default_;
}

Online Demo.

您可以在任何地方使用此解决方案,甚至在模板中:

template<typename T>
typename father::template daughter<T>::grand_son_type h()
{
     //...
     return default_;
}

希望对您有所帮助。

【讨论】:

  • 这是大量的输入和为每个不同的案例创建一个新函数,而return {}; 将适用于每个案例,正如@Troy 所说。不过,对于 C++11 之前的版本来说,这是一个不错的解决方案。
  • @cdmh:不。这不会在任何地方都有效。有关该答案,请参阅 Jesse 的 cmets。
  • 你能举个例子吗?
  • 我已经回答了为什么 Jesse 的回答不准确。 explicit 与此问题无关。
  • @cdmh 如果您不知道为什么 explicit 与此问题相关,我建议您打开一个新问题。
【解决方案3】:

typedef 怎么样?

class VeryVeryVeryLongTypeName;
typedef class VeryVeryVeryLongTypeName S;

然后使用S

HERE

【讨论】:

  • 如果返回类型是typename father::template daughter&lt;T&gt;::grand_son_type怎么办?我的解决方案仍然很有效。 ;-)
  • @Nawaz 是的,我已将此帖子标记为收藏,只是为了您的回答:D
【解决方案4】:

正如其他人所指出的,您可以依靠定义类型别名。在 C++11 中,您可以使用符号

using SnappyName = VeryVeryVeryLongTypeName;

然后在任何你想使用的地方使用SnappyName

请记住,您将需要在六个月后返回您的代码。使用可以帮助您(或您的合作者)明确理解您的意思的方法。记住:代码写一次,读多次。代码是为了以后的可读性,而不是为了节省当前的击键。

【讨论】:

  • 如果返回类型是typename father::template daughter&lt;T&gt;::grand_son_type怎么办?我的解决方案仍然很有效。 ;-)
  • 你会使用decltype / declval 来处理这样的情况吗?我认为这可能是一个很好的用例,但我还没有玩过它们。
【解决方案5】:

您收到了问题的解决方案,但您应该注意一些事项。你编写函数的方式可以防止像 NVRO 这样的复制逃避。

该标准授权编译器从临时跳过无用的副本,但它存在一些准则来匹配条件以启用优化。

在函数体中,您必须要么返回同名的对象而不是其他任何东西,要么总是返回一个对象构造。将两者混合在一起,您就会失去非常有价值的优化。

【讨论】:

    猜你喜欢
    • 2016-10-18
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    • 2021-07-28
    • 2015-03-22
    相关资源
    最近更新 更多