Здесь есть две связанные проблемы. Во-первых, обе ветви тернарного оператора должны иметь один и тот же тип (который является типом результата оператора), поэтому, если 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, который является функцией, для построения объекта и вызова его функции-члена для вывода колядки.
Вот как все это выглядит:
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
Спасибо за подсказку @rici – TeddyCode