我想通过一个构造函数传递两个值,但是我很难找到一种方法来定义我的变量,这样构造函数就可以接受这些值,构造函数本身必须保持不变。
我要传入的构造函数是:
playing_card(card_face const& f, std::optional<card_suit> const& s = std::nullopt) : face_val(f), suit_val(s)
{
if (!s.has_value() && f != card_face::white_joker && f != card_face::red_joker)
throw std::domain_error("playing card without suit must be a joker");
};
而给我错误的部分,我试图通过:
std::optional<playing_card> read_playing_card(std::istream& is)
{
std::optional<playing_card> retval;
auto face = read_card_face(is);
//auto suit;
if (face.has_value() && face != card_face::white_joker && face != card_face::red_joker)
{
auto suit = read_card_suit(is);
if (suit.has_value())
{
retval = playing_card(face, suit);
}
retval = playing_card(face);
}
if (!retval.has_value())
is.setstate(std::ios_base::failbit);
}
错误为:
a4-provided.cpp:271:39: error: no matching function for call to ‘playing_card::playing_card(std::optional<card_face>&, std::optional<card_suit>&)’
271 | retval = playing_card(face, suit);
我明白编译器在说什么,但是我不确定如何在代码中导航这个错误。
整个街区都在这里:
//=============================================================================
#include <array>
#include <istream>
#include <optional>
#include <string>
#include <sstream>
#include "a4-provided.hpp"
//=============================================================================
//
// std::optional<card_suit> read_card_suit(std::istream)
//
// read_card_suit reads a card suit from an input stream returning a
// an optional value. The return value only holds a card_suit if a valid
// card_suit was read in. If an error occurs on the stream while reading in
// the data, then stream is failed. If the character on the stream read in
// is not a valid suit, then the character read in is returned to the stream
// using is.unget().
//
std::optional<card_suit> read_card_suit(std::istream& is)
{
std::optional<card_suit> retval;
auto ch = is.get();
if (!std::istream::traits_type::eq_int_type(ch,std::istream::traits_type::eof()))
{
switch (ch)
{
case 'c':
retval = card_suit::clubs;
break;
case 'd':
retval = card_suit::diamonds;
break;
case 'h':
retval = card_suit::hearts;
break;
case 's':
retval = card_suit::spades;
break;
default:
is.unget(); // return ch to stream
is.setstate(std::ios_base::failbit); // fail the stream
}
}
else
is.setstate(std::ios_base::failbit); // fail the stream
return retval;
}
//=============================================================================
//
// Provide a simple way to generate all playing cards without requiring
// card_face, card_suit, playing_card, and all supporting operations to be
// written first.
//
std::string all_playing_cards_as_string()
{
std::array<char,4> const special_face{ 'A', 'J', 'Q', 'K' };
std::array<char,4> const suit{ 'c', 'd', 'h', 's' };
std::ostringstream buf;
// generate all numeric face cards...
for (int face=2; face != 11; ++face)
for (auto const s : suit)
buf << face << s;
// generate all special face cards...
for (auto const f : special_face)
for (auto const s : suit)
buf << f << s;
// generate two jokers (red and white)...
buf << "RW";
// return string...
return buf.str();
}
//=============================================================================
std::optional<card_face> read_card_face(std::istream& is)
{
std::optional<card_face> retval;
//retrieve char from input stream
auto ch = is.get();
//peek at the next char
auto ch2 = is.peek();
//is ch EOF ? if no, continue
if (!std::istream::traits_type::eq_int_type(ch,std::istream::traits_type::eof()))
{
switch (ch)
{
case 'A':
retval = card_face::ace;
break;
case '2':
retval = card_face::two;
break;
case '3':
retval = card_face::three;
break;
case '4':
retval = card_face::four;
break;
case '5':
retval = card_face::five;
break;
case '6':
retval = card_face::six;
break;
case '7':
retval = card_face::seven;
break;
case '8':
retval = card_face::eight;
break;
case '9':
retval = card_face::nine;
break;
case 'J':
retval = card_face::jack;
break;
case 'Q':
retval = card_face::queen;
break;
case 'K':
retval = card_face::king;
break;
case 'R':
retval = card_face::red_joker;
break;
case 'W':
retval = card_face::white_joker;
break;
case '1':
//check if ch2 = 0
if (ch2 == '0')
{
is.ignore();
retval = card_face::ten;
}
else
is.unget();
is.setstate(std::ios_base::failbit);
break;
default:
is.unget();
is.setstate(std::ios_base::failbit);
break;
}
}
else
is.setstate(std::ios_base::failbit);
if (retval.has_value())
return retval;
}
inline std::istream& operator>>(std::istream& is, card_face& s)
{
auto face = read_card_face(is);
if (face)
s = *face;
return is;
}
inline std::ostream& operator<<(std::ostream& os, card_face const& s)
{
switch (s)
{
case card_face::ace: os.put('A'); break;
case card_face::two: os.put('2'); break;
case card_face::three: os.put('3'); break;
case card_face::four: os.put('4'); break;
case card_face::five: os.put('5'); break;
case card_face::six: os.put('6'); break;
case card_face::seven: os.put('7'); break;
case card_face::eight: os.put('8'); break;
case card_face::nine: os.put('9'); break;
case card_face::ten: os.put('1'); os.put('0'); break;
case card_face::jack: os.put('J'); break;
case card_face::queen: os.put('Q'); break;
case card_face::king: os.put('K'); break;
case card_face::white_joker: os.put('W'); break;
case card_face::red_joker: os.put('R'); break;
default:
os.setstate(std::ios_base::failbit);
break;
}
return os;
}
class playing_card
{
private:
card_face face_val;
std::optional<card_suit> suit_val;
public:
playing_card() = delete;
playing_card(card_face const& f, std::optional<card_suit> const& s = std::nullopt) : face_val(f), suit_val(s)
{
if (!s.has_value() && f != card_face::white_joker && f != card_face::red_joker)
throw std::domain_error("playing card without suit must be a joker");
};
const std::optional<card_face> face() { return face_val; }
const bool has_suit() { return suit_val.has_value(); }
const std::optional<card_suit> suit()
{
if (has_suit() == true)
return suit_val;
}
friend bool operator==(playing_card const&, playing_card const&);
friend std::strong_ordering operator <=> (playing_card const&, playing_card const&);
};
std::optional<playing_card> read_playing_card(std::istream& is)
{
std::optional<playing_card> retval;
auto face = read_card_face(is);
//auto suit;
if (face.has_value() && face != card_face::white_joker && face != card_face::red_joker)
{
auto suit = read_card_suit(is);
if(suit.has_value())
{
retval = playing_card(face, suit);
}
retval = playing_card(face);
}
if (!retval.has_value())
is.setstate(std::ios_base::failbit);
}
我尝试过手动定义face
和suit
,尝试过将const
添加到变量中,尝试过混淆指针和引用,但我似乎不明白如何按照编译器想要的方式格式化它。
1条答案
按热度按时间o7jaxewo1#
编译器抱怨您将2个
std::optional
对象传递给playing_card
构造函数,而它在第2个参数中只接受1个std::optional
。更改此行:
改为:
但是,该语句是无用的,因为您在调用
retval = playing_card(face)
之后立即调用,从而丢弃了前一语句刚刚创建的对象。我怀疑您在if
上缺少了一个else
,例如:在这种情况下,您根本不需要
if
,只需无条件地调用retval = playing_card(face.value(), suit);
*。话虽如此:
read_playing_card()
、read_card_face()
和playing_card::suit()
都表现出undefined behavior,因为它们被声明为返回std::optional
对象,但并非所有代码路径都实际返回return
这样的对象。编译器应该警告您这个错误。还有,这种代码:
可以大大简化为(与
is.peek()
相同):或者甚至是这样:
同样,
playing_card::face()
返回std::optional
也没有意义,因为返回的值不能为空,因此read_card_face()
返回std::optional
也没有意义,每张牌都需要一张脸,read_card_face()
的调用者应该通过查看std::istream
的失败状态来检查读取失败,而不是函数是否返回了一个可选的(但不是真的!)face。此外,
playing_card() = delete;
是不必要的,因为playing_card
有一个用户定义的构造函数,所以编译器不会生成自己的默认构造函数。