value_or的替代方法,对返回的类型无关紧要

时间:2018-06-06 15:17:43

标签: c++ stdoptional

我已经构建了一个小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 ++的新手我做了天真的ansatz:

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

由于"Out of cards!"的类型为char*而非Card,因此失败。

我的问题:有没有办法保证优雅的oneliner没有检查和访问vaule /在两个单独的地方使用替换?

4 个答案:

答案 0 :(得分:6)

在我的选择中处理此问题的最简单方法是为operator <<添加std::optional<Card>的重载。在那里,您可以处理打印内容的逻辑,如

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();

答案 1 :(得分:4)

您可以为变体编写通用辅助函数la 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!" });

答案 2 :(得分:1)

我会使用一个函数(命名空间作用域或卡的静态成员),它接受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());

答案 3 :(得分:0)

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");

如果表现是一个问题,那么你可以做很多事情来提高效率,避免复制,但总体思路就在那里。

我应该注意到,在现实世界的情况下,您不太可能从Card中提取CarDeck并将其传输到cout。您通常也希望使用该卡执行其他操作,例如将其添加到HandPile。这需要做一些其他事情,否定你不得不多次提到价值的担忧。