Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Аноним, Вы писали:
А>>Как вывести строку текста 1000 раз не используя явного или не явного цикла ?
К>Решение с рекурсией. Голый Си. К>
Здравствуйте, shank, Вы писали:
S>Здравствуйте, 8bit, Вы писали: S>Не умаляя заслуги Кодта, но все же, эта строчка S>
S>X say[1000];
S>
S>транслируется в цикл с вызовом конструкторов... S>Кто мог знать, что это уже не подпадает под определение "неявный цикл"?
Вот декомпиляция.
Цикл есть, который создал компилятор а не программист (причем конструктора нет) !
Задача была в том что бы программист не создавал руками цикла !
.text:004010C0 push esi
.text:004010C1 push edi
.text:004010C2 mov edi, ds:??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<(std::basic_ostream<char,std::char_traits<char>> &,char const *)
.text:004010C8 mov esi, 3E8h
.text:004010CD
.text:004010CD loc_4010CD: ; CODE XREF: _main+25j
.text:004010CD mov eax, ds:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout
.text:004010D2 push offset aTest ; "test"
.text:004010D7 push eax
.text:004010D8 call edi ; std::operator<<(std::basic_ostream<char,std::char_traits<char>> &,char const *) ; std::operator<<(std::basic_ostream<char,std::char_traits<char>> &,char const *)
.text:004010DA push eax
.text:004010DB call ds:?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z ; std::endl(std::basic_ostream<char,std::char_traits<char>> &)
.text:004010E1 add esp, 0Ch
.text:004010E4 dec esi
.text:004010E5 jnz short loc_4010CD
.text:004010E7 pop edi
.text:004010E8 xor eax, eax
.text:004010EA pop esi
.text:004010EB retn
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, 8bit, Вы писали:
8>>это и есть решение без цикла, явного или не явного, с наименьшим количеством кода !
К>Это решение — не совсем "чистый" С++, поскольку пришлось определить свой класс. К>Чистое решение — вот: К>
К>Ни одной нестандартной функции, ни одного нестандартного класса.
К>Ну а то, что fill_n неявно содержит цикл — так ведь и конструктор массива содержит цикл.
"чистый" С++ я употребил что бы люди не пытались использовать всякие там BOOST, рекурсии, а так же как намек что решение скрывается в одной из основ языка (конструктуре).
То что констуктор массива содержит цикл не относится к формулировке задачи, так как
програмист его не создает этот цикл, а только обьявляет массив. Т.е. этот цикл не 'рукотворный' если можно так выразиться. Это зависит от компилятора.
У тебя, конечно же, было готово "правильное" решение. Поэтому ты закрываешь глаза на варианты. А этюд тем и интересен, чтобы решить его нестандартными способами. Это будет откровением для решающих — но и задавший задачу не должен в этом обделять ни себя, ни других.
С учётом того, что boost рискует войти в следующую версию Стандарта — BOOST_PP можно практически принять за решение.
Встречный вопрос к тебе: какими ещё способами можно решить твою задачу, кроме уже перечисленных?
— цикл
— препроцессор
— рекурсивные шаблоны
— дерево вызовов функций
— массив объектов, конструкторы с побочным эффектом
— std::fill_n + ostream_iterator
Несколько решений напрашиваются сразу.
И ещё одно решение может оказаться неочевидным Посмотрим — угадаешь ли ты, что я имею в виду.
Здравствуйте, sc, Вы писали:
К>>- массив объектов, конструкторы с побочным эффектом sc>и деструкторы тоже)
Замечательно. Одно из.
Какие ещё решения можно вписать в наши анналы? Ограничение на предельную простоту снято.
Есть ограничение на громоздкость: каждое решение должно быть минимально в своём классе.
Например, логарифмическая рекурсия в шаблонах — по основанию 2 упомянули, этого достаточно. По основанию 3 или 10 уже будет, во-первых, повтором, а во-вторых, более громоздко.
Линейная рекурсия в шаблонах — отдельный класс решения. (Правда, не всякий компилятор сможет её поднять).
Да, кстати. Маячок к неочевидному решению: <stdlib.h>
Я не закрываю глаза на варианты, очень интересно было увидеть различные способы.
Есть вот такой вариант: тоже же через конструктор но без массива,
и даже не знаю есть ли тут рекурсия или цикл (считаю что нет), думаю больше похоже на 'развернутый' массив:
class XXX
{
public:
XXX(int i, volatile int j=1)
{
j /= i;
cout << "test" << endl;
XXX a(i-1);
}
};
int main()
{
try
{
XXX a(4);
}
catch (...)
{
}
}
Здравствуйте, Кодт, Вы писали:
К>Например, логарифмическая рекурсия в шаблонах — по основанию 2 упомянули, этого достаточно. По основанию 3 или 10 уже будет, во-первых, повтором, а во-вторых, более громоздко. К>Линейная рекурсия в шаблонах — отдельный класс решения. (Правда, не всякий компилятор сможет её поднять).
Опаньки. Глаза-то у меня замылены... упомянули как раз линейную рекурсию. Для многих компиляторов — это приведёт к ICE. (Насколько помню, только comeau справлялся с глубиной 1000).
Ну раз уж я сам сказал — то приведу это решение.
Дихотомия (N/2, N-N/2) порождает много разных воплощений (instantiations), что утяжеляет работу компилятору.
Самый худший случай — когда N=2^k-1.
Здесь же будут пройдены значения f<N>, N=1000, 500, 250, 125, 63, 62, 32, 31, 16, 15, 8, 7, 4, 3, 2, 1, 0.
Здравствуйте, 8bit, Вы писали:
8>Я не закрываю глаза на варианты, очень интересно было увидеть различные способы.
8>Есть вот такой вариант: тоже же через конструктор но без массива, 8>и даже не знаю есть ли тут рекурсия или цикл (считаю что нет), думаю больше похоже на 'развернутый' массив:
8>class XXX 8>{ 8>public: 8> XXX(int i, volatile int j=1) 8> { 8> j /= i; 8> cout << "test" << endl; 8> XXX a(i-1); 8> } 8>};
8>int main() 8>{ 8> try 8> { 8> XXX a(4); 8> } 8> catch (...) 8> { 8> } 8>}
Хотя конечно компилятор развернет это в рекурсию...
Здравствуйте, 8bit, Вы писали:
8>Есть вот такой вариант: тоже же через конструктор но без массива, 8>и даже не знаю есть ли тут рекурсия или цикл (считаю что нет), думаю больше похоже на 'развернутый' массив:
Массива здесь нет, зато есть UB. В конструкторе (считай, в особой функции) создаётся локальная переменная, у которой вызывается конструктор... То есть, эти переменные — во-первых, недостроенные, а во-вторых, не образуют сплошной массив.
Процесс останавливается при делении на ноль (то самое UB).
Даже если при этом возбудится аппаратное исключение — не факт, что будет брошено асинхронное исключение С++. Это личное дело железа, ОС, компилятора, его настроек и твоих рук (иногда нужно явно регистрировать обработчик исключительных ситуаций).
Но пусть произойдёт бросок. Это приведёт к раскрутке стека, т.е., попросту, к возвратам изо всех функций.
То же самое, но более просто
// так
XXX::XXX(int N)
{
if(N==0) throw int(0); // любой тип исключения, т.к. у нас универсальная ловушка
cout << "hello\n";
}
// или так
XXX::XXX(int N)
{
if(N==0) return;
XXX x(N-1);
}
// или вот такvoid f(int N)
{
if(N==0) return;
cout << "hello\n";
f(N-1);
}
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, 8bit, Вы писали:
8>>Есть вот такой вариант: тоже же через конструктор но без массива, 8>>и даже не знаю есть ли тут рекурсия или цикл (считаю что нет), думаю больше похоже на 'развернутый' массив:
К>Массива здесь нет, зато есть UB. В конструкторе (считай, в особой функции) создаётся локальная переменная, у которой вызывается конструктор... То есть, эти переменные — во-первых, недостроенные, а во-вторых, не образуют сплошной массив. К>Процесс останавливается при делении на ноль (то самое UB).
К>Даже если при этом возбудится аппаратное исключение — не факт, что будет брошено асинхронное исключение С++. Это личное дело железа, ОС, компилятора, его настроек и твоих рук (иногда нужно явно регистрировать обработчик исключительных ситуаций). К>Но пусть произойдёт бросок. Это приведёт к раскрутке стека, т.е., попросту, к возвратам изо всех функций.
К>То же самое, но более просто К>
К>// так
К>XXX::XXX(int N)
К>{
К> if(N==0) throw int(0); // любой тип исключения, т.к. у нас универсальная ловушка
К> cout << "hello\n";
К>}
К>// или так
К>XXX::XXX(int N)
К>{
К> if(N==0) return;
К> XXX x(N-1);
К>}
К>// или вот так
К>void f(int N)
К>{
К> if(N==0) return;
К> cout << "hello\n";
К> f(N-1);
К>}
К>
К>То есть, это рекурсия.
я хотел избежать If.
Сначала именно так и написал, а потом решил через деление на ноль выйти,
раз уж мы хотим посмотреть все возможные варианты.
(так как через исключение никто не предлагал)
Но я думаю элегантнее кода нет... чем тот что был заявлен