while (temp->left->oper == '+' ||
temp->left->oper == '-' ||
temp->left->oper == '*' ||
temp->left->oper == '/' ||
temp->right->oper == '+' ||
temp->right->oper == '-' ||
temp->right->oper == '*' ||
temp->right->oper == '/')
{
// do something
}
For clarity: temp is a pointer that points to following node structure:
struct node
{
int num;
char oper;
node* left;
node* right;
};
Sure, you could just use a string of valid operators and search it.
#include <cstring>
// : :
const char* ops = "+-*/";
while(strchr(ops, temp->left->oper) || strchr(ops, temp->right->oper))
{
// do something
}
If you are concerned about performance, then maybe table lookups:
#include <climits>
// : :
// Start with a table initialized to all zeroes.
char is_op[1 << CHAR_BIT] = {0};
// Build the table any way you please. This way using a string is handy.
const char* ops = "+-*/";
for (const char* op = ops; *op; op++) is_op[*op] = 1;
// Then tests require no searching
while(is_op[temp->left->oper] || is_op[temp->right->oper])
{
// do something
}
Yes, indeed you can!
Store the valid-characters to a std::array or even a plain array and apply the standard algorithm std::any_of to it for checking the condition.
#include <array> // std::array
#include <algorithm> // std::any_of
static constexpr std::array<char, 4> options{ '+', '-', '*', '/' };
const auto tester = [temp](const char c) { return temp->left->oper == c || temp->right->oper == c; };
const bool isValid = std::any_of(options.cbegin(), options.cend(), tester);
while(isValid) // now the while-loop is simplified to
{
// do something
}
This can be more cleaned by packing into a function, which accepts the node object to be checked.
#include <array> // std::array
#include <algorithm> // std::any_of
bool isValid(const node *const temp) /* noexcept */
{
static constexpr std::array<char, 4> options{ '+', '-', '*', '/' };
const auto tester = [temp](const char c) { return temp->left->oper == c || temp->right->oper == c; };
return std::any_of(options.cbegin(), options.cend(), tester);
}
which can be called in the while-loop
while (isValid(temp)) // pass the `node*` to be checked
{
// do something
}
Create a sub function,
bool is_arithmetic_char(char)
{
// Your implementation or one proposed in another answers.
}
and then:
while (is_arithmetic_char(temp->left->oper)
|| is_arithmetic_char(temp->right->oper))
{
// do something
}
C-style:
int cont = 1;
while(cont)
switch(temp->left->oper) {
case '+':
case '-':
...
case '/':
// Do something
break;
default:
cont = 0;
}
You might need to enclose // Do something with curly braces if you're going to declare variables.
You can construct a string that contains the options and search for the character:
#include <string>
// ...
for (auto ops = "+-*/"s; ops.find(temp-> left->oper) != std::string::npos ||
ops.find(temp->right->oper) != std::string::npos;)
/* ... */;
The "+-*/"s is a C++14 feature. Use std::string ops = "+-*/"; before C++14.
Programming is the process of finding redundancies and eliminating them.
struct node {
int num;
char oper;
node* left;
node* right;
};
while (temp->left->oper == '+' ||
temp->left->oper == '-' ||
temp->left->oper == '*' ||
temp->left->oper == '/' ||
temp->right->oper == '+' ||
temp->right->oper == '-' ||
temp->right->oper == '*' ||
temp->right->oper == '/') {
// do something
}
What's the "repeated unit" here? Well, I see two instances of
(something)->oper == '+' ||
(something)->oper == '-' ||
(something)->oper == '*' ||
(something)->oper == '/'
So let's factor that repeated part out into a function, so that we only have to write it once.
struct node {
int num;
char oper;
node* left;
node* right;
bool oper_is_arithmetic() const {
return this->oper == '+' ||
this->oper == '-' ||
this->oper == '*' ||
this->oper == '/';
}
};
while (temp->left->oper_is_arithmetic() ||
temp->right->oper_is_arithmetic()) {
// do something
}
Ta-da! Shortened!
(Original code: 17 lines, 8 of which are the loop condition. Revised code: 18 lines, 2 of which are the loop condition.)
"+" "-" "*" and "/" are ASCII decimal values 42, 43, 45 and 47
thus
#define IS_OPER(x) (x > 41 && x < 48 && x != 44 && x != 46)
while(IS_OPER(temp->left->oper || IS_OPER(temp->right->oper){ /* do something */ }
Trading space against time, you could build two "Boolean" arrays indexed by temp->left->oper and temp->left->oper, respectively.
The corresponding array contains true when the condition is met, false otherwise.
So:
while (array1[temp->left->oper] || array1[temp->right->oper]) {
// do something
}
As the sets for left and right seem identical, one array will actually do.
Initialization would be like this:
static char array1[256]; // initialized to "all false"
...
array1['+'] = array1['-'] = array1['*'] = array1['/'] = '\001';
Similar for array2.
As jumps are bad for modern pipelining CPUs, you could even use a larger table like this:
while (array1[temp->left->oper << 8 | temp->right->oper]) {
// do something
}
But initialization is more tricky:
static char array1[256 * 256]; // initialized to "all false"
...
void init(char c) {
for (unsigned char i = 0; i <= 255; ++i) {
array1[(c << 8) | i] = array1[(i << 8) | c] = '\001';
}
}
init('+');
init('-');
init('*');
init('/');
Regex to the rescue!
#include <regex>
while (
std::regex_match(temp->left->oper, std::regex("[\+\-\*\/]")) ||
std::regex_match(temp->right->oper, std::regex("[\+\-\*\/]"))
) {
// do something
}
EXPLANATION: Regex brackets [] denote a regex "character class." This means "match any character listed inside the brackets." For example, g[eiou]t would match "get," "git," "got," and "gut," but NOT "gat." The backslashes are needed because plus (+) minus (-) and star (*) and forward-slash (/) have meaning within a character class.
DISCLAIMER: I don't have time to run this code; you might have to tweak it, but you get the idea. You might have to declare/convert oper from a char to a std::string.
REFERENCES
1. http://www.cplusplus.com/reference/regex/regex_match/
2. https://www.rexegg.com/regex-quickstart.html
3. https://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/0596528124/ref=sr_1_1?keywords=regex&qid=1563904113&s=gateway&sr=8-1
Putting the operators in the unordered_set will be lot efficient and will provide O(1) access to operators.
unordered_set<char> u_set;
u_set.insert('+');
u_set.insert('*');
u_set.insert('/');
u_set.insert('-');
if((u_set.find(temp->left->oper) != u_set.end()) || (u_set.find(temp->right->oper) != u_set.end())) {
//do something
}
Lambda & std::string_view
string_view gives lots of functionality of std::string and can operator on literals and it doesn't own the string.
Use Lambda instead of function for a highly local code which is not of use for the rest of the file. Also, no need to pass variables when lambda can capture them. Also get inline benefits without specifying it for a function you'd otherwise create.
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-capture-vs-overload
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rstr-view
Make char const:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rconst-immutable
auto is_arithm = [](const char c) {
return std::string_view("+-/*").find_first_of(c) != std::string::npos;
};
while (is_arithm(temp->left->oper) || is_arithm(temp->right->oper)) {
}
You can change const char c to const node *t access its oper member inside the lambda. But that is not a good idea since members of left/right of temp can be modified.
auto is_arithm2 = [](const node *t) {
return std::string_view("+-/*").find_first_of(t->oper) != std::string::npos;
};
while(is_arithm2(temp->left) || is_arithm2(temp->right)){
}
Related
This is code to find out the position of the unbalanced bracket in the given input. If there is no unbalanced bracket then the output is Success. When I output the top of the stack I get garbage values in C++. How to avoid it? Why does it happen?
Here Bracket is the struct that contains the position of the element and the type of element.
int main() {
std::string text;
getline(std::cin, text);
stack <Bracket> opening_brackets_stack;
for (int position = 0; position < text.length(); ++position) {
char next = text[position];
if (next == '(' || next == '[' || next == '{') {
Bracket *l1 = new Bracket(next, position + 1);
opening_brackets_stack.push(*l1);
cout<<opening_brackets_stack.top().type<<" "
<<opening_brackets_stack.top().position<<endl;
}
}
}
Here is the declaration of Bracket
struct Bracket
{
char type;
int position;
Bracket(char type, int position)
{
type =type;
position=position;
}
bool Matchc(char c) {
if (type == '[' && c == ']')
return true;
if (type == '{' && c == '}')
return true;
if (type == '(' && c == ')')
return true;
return false;
}
};
There's a couple of problems with your code, but to get into specifically what your issues is.
It is assigning local variables to themselves instead of to the data members.
Change
Bracket(char type, int position)
{
type =type;
position=position;
}
to
Bracket(char type, int position)
{
this->type =type;
this->position=position;
}
or use initializer lists and differing names
Bracket(char in_type, int in_position)
: type(in_type)
, position(in_position)
{
}
You also have memory leak here
Bracket *l1 = new Bracket(next, position + 1);
opening_brackets_stack.push(*l1);
this is better written with automatic storage duration as
Bracket l1{next, position + 1};
opening_brackets_stack.push(l1);
I'm trying to create a lexer for a functional language, one of the methods of which should allow, on each call, to return the next token of a file.
For example :
func main() {
var MyVar : integer = 3+2;
}
So I would like every time the next method is called, the next token in that sequence is returned; in that case, it would look like this :
func
main
(
)
{
var
MyVar
:
integer
=
3
+
2
;
}
Except that the result I get is not what I expected:
func
main(
)
{
var
MyVar
:
integer
=
3+
2
}
Here is my method:
token_t Lexer::next() {
token_t ret;
std::string token_tmp;
bool IsSimpleQuote = false; // check string --> "..."
bool IsDoubleQuote = false; // check char --> '...'
bool IsComment = false; // check comments --> `...`
bool IterWhile = true;
while (IterWhile) {
bool IsInStc = (IsDoubleQuote || IsSimpleQuote || IsComment);
std::ifstream file_tmp(this->CurrentFilename);
if (this->eof) break;
char chr = this->File.get();
char next = file_tmp.seekg(this->CurrentCharIndex + 1).get();
++this->CurrentCharInCurrentLineIndex;
++this->CurrentCharIndex;
{
if (!IsInStc && !IsComment && chr == '`') IsComment = true; else if (!IsInStc && IsComment && chr == '`') { IsComment = false; continue; }
if (IsComment) continue;
if (!IsInStc && chr == '"') IsDoubleQuote = true;
else if (!IsInStc && chr == '\'') IsSimpleQuote = true;
else if (IsDoubleQuote && chr == '"') IsDoubleQuote = false;
else if (IsSimpleQuote && chr == '\'') IsSimpleQuote = false;
}
if (chr == '\n') {
++this->CurrentLineIndex;
this->CurrentCharInCurrentLineIndex = -1;
}
token_tmp += chr;
if (!IsInStc && IsLangDelim(chr)) IterWhile = false;
}
if (token_tmp.size() > 1 && System::Text::EndsWith(token_tmp, ";") || System::Text::EndsWith(token_tmp, " ")) token_tmp.pop_back();
++this->NbrOfTokens;
location_t pos;
pos.char_pos = this->CurrentCharInCurrentLineIndex;
pos.filename = this->CurrentFilename;
pos.line = this->CurrentLineIndex;
SetToken_t(&ret, token_tmp, TokenList::ToToken(token_tmp), pos);
return ret;
}
Here is the function IsLangDelim :
bool IsLangDelim(char chr) {
return (chr == ' ' || chr == '\t' || TokenList::IsSymbol(CharToString(chr)));
}
TokenList is a namespace that contains the list of tokens, as well as some functions (like IsSymbol in this case).
I have already tried other versions of this method, but the result is almost always the same.
Do you have any idea how to improve this method?
The solution for your problem is using a std::regex. Understanding the syntax is, in the beginning, a little bit difficult, but after you understand it, you will always use it.
And, it is designed to find tokens.
The specific critera can be expressed in the regex string.
For your case I will use: std::regex re(R"#((\w+|\d+|[;:\(\)\{\}\+\-\*\/\%\=]))#");
This means:
Look for one or more characters (That is a word)
Look for one or more digits (That is a integer number)
Or look for all kind of meaningful operators (Like '+', '-', '{' and so on)
You can extend the regex for all the other stuff that you are searching. You can also regex a regex result.
Please see example below. That will create your shown output from your provided input.
And, your described task is only one statement in main.
#include <iostream>
#include <string>
#include <algorithm>
#include <regex>
// Our test data (raw string) .
std::string testData(
R"#(func main() {
var MyVar : integer = 3+2;
}
)#");
std::regex re(R"#((\w+|\d+|[;:\(\)\{\}\+\-\*\/\%\=]))#");
int main(void)
{
std::copy(
std::sregex_token_iterator(testData.begin(), testData.end(), re, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n")
);
return 0;
}
You try to parse using single loop, which makes the code very complicated. Instead i suggest something like this:
struct token { ... };
struct lexer {
vector<token> tokens;
string source;
unsigned int pos;
bool parse_ident() {
if (!is_alpha(source[pos])) return false;
auto start = pos;
while(pos < source.size() && is_alnum(source[pos])) ++pos;
tokens.push_back({ token_type::ident, source.substr(start, pos - start) });
return true;
}
bool parse_num() { ... }
bool parse_comment() { ... }
...
bool parse_whitespace() { ... }
void parse() {
while(pos < source.size()) {
if (!parse_comment() && !parse_ident() && !parse_num() && ... && !parse_comment()) {
throw error{ "unexpected character at position " + std::to_string(pos) };
}
}
}
This is standard structure i use, when lexing my files in any scripting language i've written. Lexing is usually greedy, so you don't need to bother with regex (which is effective, but slower, unless some crazy template based implementation). Just define your parse_* functions, make sure they return false, if they didn't parsed a token and make sure they are called in correct order.
Order itself doesn't matter usually, but:
operators needs to be checked from longest to shortest
number in style .123 might be incorrectly recognized as . operator (so you need to make sure, that after . there is no digit.
numbers and identifiers are very lookalike, except that identifiers starts with non-number.
I have this code to check every char in a char array if it satisfies a set number of properties:
* Is a number
* or is a (+, -, *, /)
bool chkArray(char input[]) {
for (auto x = 0; x < strlen(input); x++) {
if (isdigit(input[x]) || input[x] == '+' || input[x] == '-' || input[x] == '*' || input[x] == '/' || input[x] == ' ') {
continue;
}
else {
return false;
}
}
return true;
}
I feel like there is a more elegant way of dealing with the multiple or's that check for the (+, -, *, /). Something like this:
bool chkArray(char input[]) {
for (auto x = 0; x < strlen(input); x++) {
if (isdigit(input[x]) || input[x] == '+', '-', '*', '/', ' ') {
continue;
}
else {
return false;
}
}
return true;
}
So I am now wondering if anybody has an alternative to the original code to make it more elegant ?
Since c++14 the most idiomatic way to do that is probably to use a std::string literal and the std::string::find() function:
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
using namespace std::literals::string_literals;
int main()
{
std::string input = "Hello world5!"s;
for(auto c : input) {
std::cout << std::boolalpha
<< (std::isdigit(c) || "+-*/ "s.find(c) != std::string::npos)
<< '\n';
}
}
Output:
false
false
false
false
false
true
false
false
false
false
false
true
false
See a working example.
The oldschool solution is to use std::strchr:
if (isdigit(input[x]) || std::strchr("+-*/ ", input[x]))
Id suggest creating a function that checks if it is one of the values you want and have it return a boolean value
Something like
bool Contains(char in)
{
return in=='+' || in =='-' || in == '*' || in == '/' || in== ' ';
}
Although there are better ways to do this such as passing an array of charecters to check against instead of doing it hard coded.
I'm writing a programm which gives out the input string without its vowels.but it only gives the first charachter of the string .here is the code:
#include<iostream>
using namespace std;
int main(){
char ch;
while(cin.get(ch)){
cout<<ch;
char a=cin.peek();
while( a==65 || a==69 || a==73 || a==79 || a==85 || a==97 || a==101 || a==105 || a==111 || a==117)
cin.ignore(1 , a);
}
return 0;
}
To solve a problem like this, start by breaking the problem into smaller parts. A possible decomposition is:
Are there characters still to read from the input? No: Great, we are done!
Read in a character
Is the character a vowel? Yes: Goto 1.
Output the character
Goto 1.
Then in code, you can translate this into:
// 1) Are there characters still to read?
while (std::cin.good())
{
// 2) Read in a character
char ch;
std::cin.get(ch);
// 3) Is the character a vowel?
// For the test for a vowel, you can use something similar to
// what you have at the moment, or better still: consider
// writing a function like isVowel in #Shreevardhan answer.
if ( /* TODO: Test if the character is a vowel... */)
{
// Skip the rest of the loop and go back to 1
continue;
}
// 4) Output the good character
std::cout << ch;
// 5) Reached the end of the loop, so goto 1
}
It's a good habit to break your problem down into smaller parts. I often start a new project by first writing out a list/comments (or even drawing a flow diagram) to break up the problem into more manageable pieces.
Other answers show how to solve this problem in a more intuitive manner.
Anyway, when looking at your code consider the following:
while( a==65 || a==69 || a==73 || a==79 || a==85 || a==97 || a==101 || a==105 || a==111 || a==117)
cin.ignore(1 , a);
As you do a while loop with conditions around the value of a, and as cin.ignore(1 , a) does not change the value of a, you wont ever leave this loop unless an exception is thrown, right?
Maybe you can try to use the boost library.
#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");
Something like this
#include <iostream>
using namespace std;
bool isVowel(char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
int main() {
char c;
while (cin.get(c))
if (!isVowel(c))
cout << c;
return 0;
}
Add your storing logic inside.
A more C++-ish code
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin, s);
s.erase(remove_if(s.begin(), s.end(), [](char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}), s.end());
cout << s;
return 0;
}
See a demo.
I made this program just out of interest and wanted to make it better. My problem is that I want to make a nested for-loop to carry out the iterations but I can't get my head around it, I have tried many times but my head is melting. Any help would be greatly appreciated. Also for some reason on windows and openSuse (from what I have seen) the program prints out some random characters after the expected output, a solution to this would be a great bonus. Thanks !
Sorry I didn't make it clearer, the point of the code is to be able to theoretically generate every combination of letters from AAAAAAAA to ZZZZZZZZ.
1) No it's not homework
#include <iostream>
using namespace std;
int main()
{
char pass [] = {'A','A','A','A','A','A','A','A'};
while(pass[0] != '[')
{
pass[7]++;
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
if(pass[6] == '[')
{
pass[6] = 'A';
pass[5]++;
}
if(pass[5] == '[')
{
pass[5] = 'A';
pass[4]++;
}
if(pass[4] == '[')
{
pass[4] = 'A';
pass[3]++;
}
if(pass[3] == '[')
{
pass[3] = 'A';
pass[2]++;
}
if(pass[2] == '[')
{
pass[2] = 'A';
pass[1]++;
}
if(pass[1] == '[')
{
pass[1] = 'A';
pass[0]++;
}
cout << pass << endl;
}
return 0;
}
Maybe like this:
const char char_first = 'A';
const char char_last = '[';
const unsigned int passlen = 8;
while (pass[0] != char_last)
{
++pass[passlen - 1];
for (unsigned int i = passlen - 1; i != 0; --i)
{
if (pass[i] == char_last)
{
++pass[i - 1]; // OK, i is always > 0
pass[i] = char_first;
}
}
}
For printing, include <string> and say:
std::cout << std::string(pass, passlen) << std::endl;
I took the liberty of making a few of the magic numbers into constants. If you're ever going to refactor this into a separate function, you'll see the merit of this.
Since (to output it) you use pass as a C string, it should be null terminated. Since it is not, garbage is printed. So you could define it as:
char pass [] = {'A','A','A','A','A','A','A','A','\0'};
or simpler
char pass[] = "AAAAAAAAA";
I'd forget about carrying on my own and just convert to/from numbers. What you're doing here is basically printing a numbers whose digits range from 'A' to ']', mappable to 0-28 via the magic of ASCII (why no ^ in passwords?)
Printing the number of anything then really boils down to
#include <iostream>
#include <cmath>
using namespace std;
std::string format(long num, int ndigits) {
if(ndigits == 0) {
return "";
} else {
char digit = 'A' + num % 28;
return format(num / 28, ndigits - 1) + digit;
}
}
int main()
{
for(int i = 0 ; i < powl(28,8) ; ++i) {
cout << format(i, 8) << endl;
}
}
You may still want to work in a char array instead of producing a billion temporary strings if you're serious about the loop, but the principle stays the same.
First try to find the common parts in the expressions looking like
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
You should think along a line like "There's always the same number here, and a one-lower number there". Then, you replace that notion of a number with a variable and find out which range the variable has. KerrekSB gave you a solution, try to arrive at similar code from your own reasoning.
You just have to play a bit with your while and make it fit a for-loop.
while(pass[0] != '[') becomes for (i=0; pass[0] != '['; i++)
then you can replace all ifs with only one:
if(pass[i+1] == '[')
{
pass[i+1] = 'A';
pass[i]++;
}
How did we come to that conclusion? Well if you check all your if-statements all that changes between them is the indices. You can see clearly that pattern so you just replace the indices with a variable.
For starters, this is definitely not a case for a nested loop. In fact,
your entire code boils down to:
pass = initialPattern();
while ( isValidPattern( pass ) ) {
nextPattern( pass );
std::cout << pass << std::endl;
}
(But I wonder if you don't really mean to do the output before the
increment.)
Now all you have to do is define the type of pass and relevant
functions; you might even consider
putting everything in a class, since all of the functions operate on the
same data instance.
Judging from your code, pass should be an std::string with 8
characters; the initialization could be written:
std::string pass( 8, 'A' );
isValidPattern apparently only looks at the first character. (I'm not
sure that's correct, but that's what your code does.) Something like:
bool
isValidPattern( std::string const& pattern )
{
return pattern[0] != '[';
}
according to your code, but something like:
struct NotIsUpper
{
bool operator()( char ch ) const
{
return ! ::isupper( static_cast<unsigned char>( ch ) );
}
};
bool
isValidPattern( std::string const& pattern )
{
return pattern.size() == 8
&& std::find_if( pattern.begin(), pattern.end(), NotIsUpper() )
== pattern.end();
}
would seem more appropriate. (Of course, if you're doing any sort of
coding with text, you'd already have NotIsUpper and its siblings in
your tool kit.)
Finally, nextPattern seems to be nothing more than a multi-digit
increment, where the data is stored in big-endian order. So the
following (classical) algorithm would seem appropriate:
void
nextPattern( std::string& pattern )
{
static char const firstDigit = 'A';
static char const lastDigit = 'Z';
static std::string const invalidPattern( 1, '[' );
std::string::reverse_iterator current = pattern.rbegin();
std::string::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit ) {
*current = firstDigit;
++ current;
}
if ( current != end ) {
++ *current;
} else {
pattern = invalidPattern;
}
}
Formally, there is no guarantee in the standard that the letters will
be encoded in sequential ascending order, so for maximum portability,
you probably should in fact use an std::vector<int> with values in the
range [0, 26), and map those to letters just befor output. This
would be trivial if you put all of these operations in a class, since
the internal representation wouldn't be visible to the client code.
Something like:
class PatternGenerator
{
std::vector<int> myData;
public:
explicit PatternGenerator()
: myData( 8, 0 )
{
}
void next()
{
static int const lastDigit = 26;
std::vector<int>::reverse_iterator current = pattern.rbegin();
std::vector<int>::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit - 1 ) {
*current = 0;
++ current;
}
if ( current != end ) {
++ *current;
} else {
myData.front() = lastDigit;
}
}
bool isValid() const
{
return myData.front() < lastDigit;
}
friend std::ostream& operator<<(
std::ostream& dest, PatternGenerator const& obj )
{
static char const characterMap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ( std::vector<int>::iterator current = obj.myData.current();
current != obj.myData.end():
++ current ) {
dest << characterMap[*current];
}
return dest;
}
};
(Note that things like isValid become simpler, because they can depend on the class invariants.)
Given this, all you have to write is:
int
main()
{
PatternGenerator pass;
while ( pass.isValid() ) {
std::cout << pass << std::endl;
pass.next();
}
return 0;
}
To do nested loops, you need to turn it inside-out.
You've written the code thinking as follows: go through all the possibilities for the last symbol, then change the second-last once and go back, etc. That's like counting up from 1, getting to 10 and putting a 1 in the tens column, etc.
Nested loops work the other way: go through the possibilities for the first symbol, allowing the inner loops to take care of possibilities for the other symbols each time. i.e., "list all those numbers, in order, that start with 0 in the millions place, then the ones that start with 1 etc.". In the outermost loop, you just set that value for the first digit, and the nested loops take care of the rest.