替代对返回类型漠不关心的value_or

Alternative to value_or that is indifferent to the returned type

本文关键字:value or 漠不关心 返回类型      更新时间:2023-10-16

我构建了一个小类Card重载<<运算符,基本上打印出花色和卡片的值。

实现细节与我想在这里问的问题无关,只是假设显而易见的。Card我建立了一个类CardDeck。当然,CardDeck可能会用完卡片。这促使我进行这种尝试:

std::optional<Card> CardDeck::drawCard() {
if (this->Cards.empty()) {
return std::nullopt;
}
else {
Card card = this->Cards.front();
this->Cards.pop_front();
return std::optional<Card>{card};
}
}

现在可以抽一张牌了,处理空牌组的可能性是使用CardDeck的客户端代码的责任,但该方法并不总是返回值是冗长的。我喜欢这个解决方案。

无论如何,我做了天真的安萨茨C++新手:

std::cout<< cardDeck.drawCard().value_or("Out of cards!");

此操作失败,因为"Out of cards!"的类型char*但不是Card

我的问题:有没有办法在不检查和访问vaule/在两个不同的地方使用替代品的情况下保护优雅的oneliner?

在我的观点中处理这个问题的最简单方法是为std::optional<Card>添加operator <<重载。 在那里,您可以处理要打印的逻辑

std::ostream& operator <<(std::ostream& os, const std::optional<Card>& card)
{
if (card == std::nullopt)
return os << "Out of cards!";
else
return os << *card;
}

然后你可以拥有

std::cout << cardDeck.drawCard();

你可以为变量编写通用辅助std::visit函数,但对于std::optional,如下所示:

template <typename T, typename F, typename FEmpty>
auto my_optional_visit(const std::optional<T>& o, F f, FEmpty fEmpty)
{
return o ? f(*o) : fEmpty();
}

然后:

my_optional_visit(cardDeck.drawCard(),
[](const Card&c){ std::cout << c; },
[](){ std::cout << "Out of Cards!" });

我会使用一个函数(命名空间范围或卡片的静态成员(,该函数接受std::optional<Card>并将其文本表示形式作为字符串返回。相关位将是:

class Card {
...
std::string repr() const {
std::string cr;
// writes the textual representation of a card here
return cr;
}
static std::string repr(const std::optional<Card> &card) {
if (card.has_value()) {
return card.value().repr();
}
return "Out of cards!";
}
};
std::ostream& operator << (std ostream& out, const Card& card) {
out << card.repr();
}

然后,您只需使用:

std::cout << Card::repr(cardDeck.drawCard());

C++函数只能有一个返回类型。在您的情况下,您希望在运行时确定结果的类型,每次调用结果时结果的类型可能会有所不同。这是不可能的。

如果你需要经常这样做,我建议只创建一个小的包装函数。

std::string optionalCardToString(const std::optional<Card> & card,
const std::string & emptyString) {
return card ? card->to_string() : emptyString;
}
std::cout << optionalCardToString(cardDeck.drawCard(), "Out of Cards");

如果性能是一个问题,你可以做很多事情来提高效率以避免制作副本,但总体思路是存在的。

我应该注意,在现实世界中,您不太可能从CarDeck中绘制Card并将其传送到cout。您通常还想对卡执行其他操作,例如将其添加到HandPile。这种需要做其他事情会否定你对必须多次提及值的担忧。

相关文章: