实际上这里有两个相关的问题。首先,三元运算符的两个分支需要具有相同的类型(这是运算符结果的类型),所以如果Christmas
返回string
,则不能有三元运算符的另一个分支返回ostream&
。
第二个问题恰恰就是Christmas
涉嫌返回string
。 (我假设return语句实际上在Christmas
函数中。)函数的目的不是返回string
,而是返回字符串,并且递归地返回其他字符串到cout
。所以唯一有意义的返回类型是ostream&
或void
。但是,如果您进行了这样的更改,则会发现cout << Christmas(...)
是错误的,因为您无法向自己发送(<<
)流。
看到如何用ostream&
返回来解决这个问题很有意思,尽管它最终看起来与当前的程序截然不同。以下内容本质上是有缺陷的,因为像Christmas
这样的函数应该能够输出到任何流,但我们稍后可以修复。我们首先假设该函数返回一个ostream&
,并且它也输出到相同的ostream
。由于该函数返回ostream&
,我们应该用这个来代替cout
,所以我们可能有一些大致是这样的:
std::ostream& Christmas(int day, int count, bool startStanza) {
return (/* We're not finished */)
? Christmas(/* the next line */) << /* This line */;
: std::cout; /* FIXME */
}
然而,递归现在已经被颠覆了。递归调用发生在之前我们设法将当前行发送到返回的ostream
。所以我们实际上需要从最后开始,并在开始时递减。事实证明,这并不困难,我们甚至可以摆脱布尔:
std::ostream& Christmas(int day, int count) {
return day ? count <= day ? Christmas(day, count + 1) << gift[count] << '\n'
: Christmas(day - 1, 1) << "On the "
<< day
<< " day of Christmas, "
"my true love gave to me:\n"
: std::cout; /* FIXME */
}
如果我们要使用<<
,我们不妨是一致的。假设我们想通过写作来启动整个事情关闭:
std::cout << Christmas;
要做到这一点,我们需要两样东西:
一个类的对象,持有ostream&
,它具有类似的成员函数到上面。
I/O manipulator是一个函数,用于构造对象并调用其成员函数来输出carol。
这里的一切的样子:
class Singer {
friend std::ostream& Christmas(std::ostream& out);
Singer(std::ostream& out) : out(out) {}
std::ostream& sing(int day, int count) {
return day ? count <= day ? sing(day, count + 1) << (count == 1 && day > 1 ? "and " : "")
<< gift[count - 1] << '\n'
: sing(day - 1, 1) << "\nOn the "
<< day
<< "th day of Christmas, "
"my true love gave to me:\n"
: out;
}
private:
std::ostream& out;
static const char *gift[12];
};
std::ostream& Christmas(std::ostream& out) { return Singer(out).sing(12,1); }
亲身体验:http://coliru.stacked-crooked.com/a/1f801eadf8f5261e
你可能是指'dayCheck == FALSE'(我认为这是更好的写作'dayCheck',除非你按照“使用枚举而不是布尔值来指示使用哪种替代方法”的风格建议。这是您的问题的一个侧面问题。 – rici 2014-09-30 05:14:08
感谢提示@rici – TeddyCode 2014-09-30 06:00:48