Creating an Interactive Prompt in C++ - c++

I have a program which should read commands from the console and depending on the command perform one of several actions. Here is what I have so far:
void ConwayView::listening_commands() {
string command;
do {
cin >> command;
if ("tick" == command)
{
// to do
}
else if ("start" == command)
{
// to do for start
}
...
} while (EXIT != command);
}
Using a switch in place of the if statements helps a little if there are a large amount of commands. What patterns do you suggest using to provide the interactive command line?

There are multiple ways to solve this and it's debatable what the "right" solution is. If I were to solve it for my own work, I would create a table of a custom struct. Something like:
struct CommandStruct {
char *command;
int (*commandHandler)(/*params*/);
} commandTable[] = {
{ "tick", tickCommand },
{ "start", startCommand },
...
};
Then my processing loop would walk through each element of this table, looking for the right match, such as:
for (int i = 0; i < TABLE_SIZE; ++i) {
if (command == commandTable[i].command) { /* using whatever proper comparison is, of course */
commandTable[i].commandHandler(/*params*/);
break;
}
}

Not really a pattern, but often a good approach:
#include <map>
#include <functional>
#include <string>
#include <iostream>
typedef std::map< std::string, std::function<void(void)> > command_dict;
// ^^^^^^^^
// the signature of your commands. probably should have an error code.
void command1() { std::cout << "commanda" << std::endl; }
void command2() { std::cout << "commandb" << std::endl; }
void command3() { std::cout << "commandc" << std::endl; }
int main() {
command_dict c;
c["a"] = &command1;
c["b"] = &command2;
c["c"] = &command3;
std::string input;
while(std::getline(std::cin, input)) { // quit the program with ctrl-d
auto it = c.find(input);
if(it != end(c)) {
(it->second)(); // execute the command
} else {
std::cout << "command \"" << input << "\" not known" << std::endl;
}
}
}

If the number of command is small and possible parameters are really few, you could keep on with switch case !
If the number of commands increases, consider the command design pattern (which is IMHO some sort of strategy pattern disguised: cf Using a strategy pattern and a command pattern for the differences between command and strategy patterns).
If most of your commands are all sharing a part of the same behaviour, don't forget the template method pattern.
If the complexity for creating your command objects increases ( i.e. there is complexity in decoding/understanding the input of your command line), you should start looking at the interpreter design pattern
If while designing with the help of the interpreter pattern, you happen to see some complexity ( if the interpreter needs too much work, you see syntax issues and so on ), then you should probably look at DSL, domain specific language, and design your own language that fits (and only fits) to you own inputs.

The if-else ladder is fine.
It can in principle be replaced with a map<string, Function>, but that gains you nothing for this concrete case (it is added complexity for no particular gain, even with a high number of commands).
When I wrote this initially I forgot to mention though:
Make your command handlers separate functions.
If you don’t, then the if-else ladder can become quite messy… The map solution requires separate functions, and can therefore appear to be a little more clean than an everything-directly-here if-else ladder. But it’s really the separate functions that then provide a measure of clarity, while the map detracts a little (adding extra work in maintaining the map, and an extra level of indirection to cope with).
On the other hand, since “read commands from the console” indicates interactive input, with a user in the picture, you don’t want to read two or more commands from the same line of input. Because that would screw up the prompting, and can seem quite baffling to the user. So instead of reading a “word” of input at a time using >>, use std::getline to a read a full line of input at a time.

Use the new and improved way to preform a bunch of commands at will:
int happy_time = 5;
int a = happy_time;
int muddy_dirt = 1;
int b = muddy_dirt;
int c = happy_time * muddy_dirt //really messy stuff
that's probably the least complicated way to do it...

You must use database like access if your command is large.

Related

What is the point in returning values?

I'm fairly new when it comes to C++ so bear with me. When learning about return values in functions, I was told that the proper way to write pure functions is to return a value every time. I attempted this in a small function that checks the user's age and returns whether or not they're an adult. The issue here, at least for me, is understanding the proper utilization of these return values. For example, in this code snippet here I'm returning whether or not they are an adult given their age in years.
main.h
#pragma once
#define LOG(x) std::cout << x
#define LOGCIN(x) std::cin >> x
bool check_age(int age) {
if (age >= 18)
return true;
else
return false;
}
main.cpp
#include <iostream>
#include "main.h"
bool check_age(int age);
int main() {
int age;
LOG("Enter your current age in years: ");
LOGCIN(age);
bool adult = check_age(age);
if (adult == true) {
LOG("You are an adult!");
} else {
LOG("You are not an adult!");
}
}
However, when I rewrote this code without using return values, I got this.
main.h
#pragma once
#define LOG(x) std::cout << x
#define LOGCIN(x) std::cin >> x
void check_age(int age) {
if (age >= 18)
LOG("You are an adult!");
else
LOG("You are not an adult!");
}
main.cpp
#include <iostream>
#include "main.h"
void check_age(int age);
int main() {
int age;
LOG("Enter your current age in years: ");
LOGCIN(age);
check_age(age);
}
As you can see, the latter code choices is simpler and more compact. If code requires more lines and takes longer to write with return values, then what's even the point in using them?
Often the purpose of a function is not just to log something to cout but instead make a decision based on some parameters, or return a value so it can be used flexibly. An example of this would be in binary search:
while(l <= r) {
int mid = (l+r)>>1;
if(check(/* parameters */)) {
//update answer
r = mid+1;
} else l = mid-1;
}
Of course, you could make your function edit a global variable and make decisions based off of that; but it will make the code more verbose:
while(l <= r) {
int mid = (l+r)>>1;
check(/* parameters */);
if(ok /* global variable*/) {
//update answer
r = mid+1;
} else l = mid-1;
}
As an additional example, it is a lot easier to write (and read):
round(a)+ceil(b)
than have these functions update global variables.
Imagine the function is provided by someone else.
In that case, we may not be able to know its implementation.
How does our program know whether the function succeeds or not?
Besides, sometimes we want to know some information from a function. I think that's why return values are used.
Returning a value from the function serves an important purpose - it allows you to separate the two concepts of "determine whether this person is an adult" and "print some stuff about this person".
You could imagine tons of scenarios where the program would need to know if someone was an adult without printing it to console - such as allowing them to buy alcohol, register for college, etc etc etc.
And you could also imagine that if you knew someone was an adult, there might be a ton of different ways you'd like to print that (imagine other languages, or rendering it on a webpage, or etc etc).
So by returning the value, you enable this separation of concepts which makes your code much more flexible in the future.
Maybe you don't need that for a toy example, but that's sorta beside the point when you're asking a broad design question like this.

C++ - Pointer to local variable within the function

I know this can look like a rookie question already asked a thousand time. But I searched for the exact answer and I haven't found one...
I'm working on a code that, to sum up, fill an XML with different data.
I'm trying to optimize a part of it. The "naïve" code is the following:
xml << "<Node>";
for(auto& input : object.m_vec)
{
if(input == "Something")
{
xml << input;
}
}
xml << "</Node>";
for(auto& input : object.m_vec)
{
if(input == "SomethingElse")
{
xml << "<OtherNode>";
xml << input;
xml << "</OtherNode>";
break;
}
}
The important thing is, while more than one input fit in <Node></Node>, only one fit in <OtherNode></OtherNode> (explaining the break;) and it may not exist either (explaining the xml << in-between the if statement).
I think I could optimize it such like:
std::vector<std::string>* VecPointer;
xml << "<Node>";
for(auto& input : object.m_vec)
{
if(input == "Something")
{
xml << input;
}
else if(input == "SomethingElse")
{
VecPointer = &input;
}
}
xml << "</Node>";
if(!VecPointer->empty())
{
xml << "<OtherNode>"
<< *VecPointer
<< "</OtherNode>";
}
The point for me here is that there is no extra memory needed and no extra loop. But the pointer to the local variable bothers me. With my beginner's eyes I can't see a case where it can lead to something wrong.
Is this okay? Why? Do you see a better way to do it?
You need to make sure your compairson also looks for an existing value within the VecPointer, since your original second loop only cares about the first value it comes across.
else if(VecPointer && input == "SomethingElse")
Don't look for ->empty(), as that's accessing the pointer and asking whether the pointed to vector is empty. If there's nothing to point to in the first place, you're going to have a bad time at the -> stage of the statement. Instead, if against it, since it's a pointer.
if(VecPointer)
Finally, you're using a Vector to save that one value from m_vec, which from other code I'm assuming is not a vector<vector<string>> but a vector<string> - in the latter case, your VecPointer should be std::string*
std::string* VecPointer = nullptr;
I'm trying to optimize a part of it.
...
Is this okay?
Maybe not! This may already be a poor use of your time. Are you sure that this is what's hurting your performance? Or that there's a performance problem at all?
Remember Don Knuth's old adage: Premature optimization is the root of all evil...
Do you see a better way to do it?
Consider profiling your program to see which parts actually take up the most time.
On an unrelated note, you could use standard library algorithms to simplify your (unoptimized) code. For example:
if (std::ranges::find(std::begin(object.m_vec) std::end(object.m_vec), "SomethingElse"s )
!= std::end(object.m_vec))
{
xml << "<OtherNode>" << whatever << "</OtherNode>";
}

Code generation from template file

I have written a template file which is as follows
Hello ${Name}
I like ${food}
I wanted to write a c++ code which generates the following code using the template file as reference
Hello John
I like Pasta
I like Pasta
I like Pasta
Is there a way to do this in C++? I came across "ctemplate", but I was not convinced.
The application I am developing is cross-platform.
( I wanted to do something like string template in c#)
I've written a template expansion 'engine' using Boost Spirit before:
Compiling a simple parser with Boost.Spirit
It's really versatile
supports nested expansions
supports recursive expansions
supports dynamic expansions (e.g. if you want a variable to be expanded with a different value depending on the context)
I've just adapted it to your question's macro syntax. See it Live On Coliru
Update
Okay, since performance appears to be the primary goal, here's a highly optimized expansion engine, in a benchmark:
#include <string>
#include <sstream>
#include <map>
#include <boost/utility/string_ref.hpp>
template <typename Range>
std::string expand(Range const& key)
{
if (key == "Name")
return "John";
if (key == "food")
return "Pasta";
return "??";
}
#include <iostream>
int main()
{
static const std::string msg_template =
"Hello ${Name}\n"
"I like ${food}\n"
;
std::ostringstream builder;
builder.str().reserve(1024); // reserve ample room, not crucial since we reuse it anyways
for (size_t iterations = 1ul << 22; iterations; --iterations)
{
builder.str("");
std::ostreambuf_iterator<char> out(builder);
for(auto f(msg_template.begin()), l(msg_template.end()); f != l;)
{
switch(*f)
{
case '$' :
{
if (++f==l || *f!='{')
{
*out++ = '$';
break;
}
else
{
auto s = ++f;
size_t n = 0;
while (f!=l && *f != '}')
++f, ++n;
// key is [s,f] now
builder << expand(boost::string_ref(&*s, n));
if (f!=l)
++f; // skip '}'
}
}
default:
*out++ = *f++;
}
}
// to make it slow, uncomment:
// std::cout << builder.str();
}
std::cout << builder.str();
}
It runs 2^22 (4,194,304) iterations in ~0.775s
See it Live On Coliru too (where it runs in ~1.8s).
The standard libraries have excellent facilities for everyday regex parsing (which is what you need), take a look at the docs here.
You need to learn about regex if you've never heard of it - this is at least one place outlining the details.
Alternately if you are concerned with performance and your task is literally as simple as you describe then writing your own parser should be very straight forward using two streams and seeking forward for the ${ escape sequence while copying across to the output stream substituting as needed.

C++: Redirect code to certain position

I am very new to C++.
How I can "redirect" code to certain position?
Basically, what should I put instead of comments lines here:
if ( N>1 ) {
// What should be here to make the code start from the beginning?
}
else {
// What should be here to make the code start from certain point?
}
I understand that C++ is not scripting language, but in case the code is written as script, how I can make redirect it?
Thank you
A goto command will do what you want but it's generally frowned on in polite circles :-)
It has its place but you would be possibly better off learning structured programming techniques since the overuse of goto tends to lead to what we call spaghetti code, hard to understand, follow and debug.
If your mandate is to make minimal changes to code which sounds like it may already be badly written, goto may be the best solution:
try_again:
n = try_something();
if (n > 1)
goto try_again;
With structured programming, you would have something like:
n = try_something();
while (n > 1)
n = try_something();
You may not see much of a difference between those two cases but that's because it's simple. If you end up with your labels and goto statements widely separated, or forty-two different labels, you'll beg for the structured version.
Use functions, loops etc to control the "flow" of your application. Think about code as reusable pieces, anything that is going to be reused should be placed in a function or looped through.
Here is an example:
void main()
{
int i = 0;
SayHello();
if (i < 1)
{
SayHello();
i++;
}
else
{
SayGoodbye();
}
}
void SayHello()
{
cout << "Hello" << endl;
}
void SayGoodbye()
{
cout << "Goodbye" << endl;
}
I'm not entirely certain what you mean by "redirect", but consider the following:
if (N > 1) {
speak();
} else {
do_something_else();
}
as paxdiablo has already stated the goto method isn't good practice. It would be better to use functions that do a specific thing, this way debugging is easier and someone can actually follow what your code is doing (or at least what it is supposed to do).

Checking lists and running handlers

I find myself writing code that looks like this a lot:
set<int> affected_items;
while (string code = GetKeyCodeFromSomewhere())
{
if (code == "some constant" || code == "some other constant") {
affected_items.insert(some_constant_id);
} else if (code == "yet another constant" || code == "the constant I didn't mention yet") {
affected_items.insert(some_other_constant_id);
} // else if etc...
}
for (set<int>::iterator it = affected_items.begin(); it != affected_items.end(); it++)
{
switch(*it)
{
case some_constant_id:
RunSomeFunction(with, these, params);
break;
case some_other_constant_id:
RunSomeOtherFunction(with, these, other, params);
break;
// etc...
}
}
The reason I end up writing this code is that I need to only run the functions in the second loop once even if I've received multiple key codes that might cause them to run.
This just doesn't seem like the best way to do it. Is there a neater way?
One approach is to maintain a map from strings to booleans. The main logic can start with something like:
if(done[code])
continue;
done[code] = true;
Then you can perform the appropriate action as soon as you identify the code.
Another approach is to store something executable (object, function pointer, whatever) into a sort of "to do list." For example:
while (string code = GetKeyCodeFromSomewhere())
{
todo[code] = codefor[code];
}
Initialize codefor to contain the appropriate function pointer, or object subclassed from a common base class, for each code value. If the same code shows up more than once, the appropriate entry in todo will just get overwritten with the same value that it already had. At the end, iterate over todo and run all of its members.
Since you don't seem to care about the actual values in the set you could replace it with setting bits in an int. You can also replace the linear time search logic with log time search logic. Here's the final code:
// Ahead of time you build a static map from your strings to bit values.
std::map< std::string, int > codesToValues;
codesToValues[ "some constant" ] = 1;
codesToValues[ "some other constant" ] = 1;
codesToValues[ "yet another constant" ] = 2;
codesToValues[ "the constant I didn't mention yet" ] = 2;
// When you want to do your work
int affected_items = 0;
while (string code = GetKeyCodeFromSomewhere())
affected_items |= codesToValues[ code ];
if( affected_items & 1 )
RunSomeFunction(with, these, params);
if( affected_items & 2 )
RunSomeOtherFunction(with, these, other, params);
// etc...
Its certainly not neater, but you could maintain a set of flags that say whether you've called that specific function or not. That way you avoid having to save things off in a set, you just have the flags.
Since there is (presumably from the way it is written), a fixed at compile time number of different if/else blocks, you can do this pretty easily with a bitset.
Obviously, it will depend on the specific circumstances, but it might be better to have the functions that you call keep track of whether they've already been run and exit early if required.