【问题标题】:What can I return which is valid for every type of <T>?我可以返回什么对每种类型的 <T> 都有效?
【发布时间】:2021-05-21 09:40:04
【问题描述】:

我有一个简单的模板函数实现,用于从队列中返回前面的元素。

template<class T>
T Queue<T>::front(){  //Queue is a typical class implementation of queue
    if(head)          //head points to first element
        return head->data;   //head->data is of type T
    //else return -1  //I want to do something like this 
}

如果队列不为空,则返回第一个元素。我知道front() 可以在队列为空的情况下不返回任何内容而工作,但我想返回一些内容,以便我可以知道队列是否为空(以及摆脱编译器警告)。

问题- 当队列为空时,我可以返回什么?由于它的返回类型是 T,所以我不能为所有类型的 T 返回预定义的值(如 bool 或 int)。

【问题讨论】:

  • 抛出异常?
  • 这是 C++17 吗?你可以回std::optional&lt;T&gt;
  • 你不能那样做。
  • 你可以返回一个默认构造的T,但这并不能真正解决问题,并且对T施加了不必要的限制

标签: templates queue c++17


【解决方案1】:

对于每种类型的&lt;T&gt;,我可以返回什么有效?

C++ 标准库中使用的一个典型设计是返回一个迭代器。这个设计例如在find中使用。

另一个设计是返回一个引用。例如,这与 frontat 以及下标运算符一起使用。

问题-当队列为空时我可以返回什么?

在迭代器设计中,通常会将迭代器返回到最后一个元素之后的位置。

在参考案例中,您无法返回任何内容,因为没有可参考的内容。在这个设计中,有几种替代方案,标准库在不同的上下文中使用了一些替代方案:

  • 记录函数的前提条件,即当容器为空时不能调用该函数。如果调用者违反了前置条件,那么程序的行为将是未定义的。这是标准库与front 和下标运算符一起使用的方法。
  • 将这种情况视为错误。在 C++ 中设计错误处理的方法有很多,但典型的选择是抛出异常。这就是标准库在 at 的情况下所做的事情。

另一种在标准库中没有太多使用的设计是返回std::optional&lt;T&gt;,并在空的情况下返回std::nullopt


我知道 front() 可以工作而不返回任何东西

这是一个潜在的误解。例如,您可以抛出而不是返回。或者您可以结束该过程。但是在没有returnthrow 的情况下让执行流出函数将导致未定义的行为。

【讨论】:

  • 嗯... STL 容器通常使用 beginend 来返回迭代器,而 frontback 确实返回元素或在空容器上调用 UB。
  • @Aconcagua 问题是“我能返回什么对每种类型都有效”。您返回的内容取决于上下文。标准库在不同的上下文中使用了许多返回类型。
  • 如果采用迭代器概念,也许只是添加建议重命名函数以满足 STL 命名模式。这样可以避免用户方面的混乱。
  • @Aconcagua 我添加了标准库使用不同设计的示例。
  • 这些都很好,但这不是我的意思(看来我需要学会更清楚地表达自己......)。 front 返回引用很好,与 STL 中的语义相同。 front 返回迭代器是有问题的,因为 STL 在那种情况下使用 begin。因此,我会向 if 使用迭代器添加一个建议,而更喜欢名称 begin,这将再次符合 STL。
【解决方案2】:

你可以:

  • 返回一个有条件为空的指针。
  • 抛出异常。
  • 记录它是未定义的行为。

取决于您的项目已有的约定。另一件事是您按值返回元素,这可能不是正确的调用。

【讨论】:

  • 你能解释一下为什么这种情况下按值返回是不对的吗?
  • @avm 主要原因是人们可能想要访问元素本身,而不是它的副本。
  • 是的,你是对的。如果有人想修改 front() 中的值,他们可能无法在 front() 按值返回时这样做。
猜你喜欢
  • 1970-01-01
  • 2021-01-31
  • 2014-04-03
  • 1970-01-01
  • 2016-07-23
  • 2019-06-13
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
相关资源
最近更新 更多