I'm new to c++ and I'm writing a program that executes certain commands. My program is supposed to have about 200 commands and using strcmp to check if the string is one among the command seems to be slow and inaccurate to me. I'm wondering if there's a function that could call the given input directly as a command.
For example:
void main() {
char test[60], param[10];
std::cin >> test >> param;
callFunction(test, param);
}
NOTE : I've done some search already and found a way using maps, but what if the number of arguments for each function differs? Any help would be appreciated, thanks!
It would be a good coding practice to create a class for each command and inherit those classes from a common base class with a virtual function taking a vector of arguments. In your case the arguments are strings, so the command processing methods can take a vector of strings as arguments and return e.g. program exit code. Then comes a map, more specifically a hash table which is unordered_map in C++ because ordered iteration doesn't seem needed here. In that unordered_map the keys are lowercase command names and values are pointers to the instance of the class processing that command. The source code example is below:
#include <unordered_map>
#include <string>
#include <cstdint>
#include <vector>
#include <iostream>
#include <memory>
enum class ExitCode : int32_t
{
OK = 0,
WRONG_USAGE = 1,
// Change the values below to your specific error (exit) codes
SOME_ERROR = 2,
OTHER_ERROR = 3
};
class CommandProcessor
{
public:
virtual ExitCode Go(const std::vector<std::string>& parameters) = 0;
};
class FooCommandProcessor : public CommandProcessor
{
public:
virtual ExitCode Go(const std::vector<std::string>& parameters) override
{
// Implement processing of Foo command here
return ExitCode::OK;
}
};
class BarCommandProcessor : public CommandProcessor
{
virtual ExitCode Go(const std::vector<std::string>& parameters) override
{
// Implement processing of Bar command here
return ExitCode::OK;
}
};
// Implement classes processing the other commands here
class CommandSelector
{
typedef std::unordered_map<std::string, std::shared_ptr<CommandProcessor>>
StringCommandProcessorMap;
StringCommandProcessorMap _scpm;
template <class CP> void RegisterCommand(const std::string& command)
{
_scpm.insert(StringCommandProcessorMap::value_type(
command, std::shared_ptr<CommandProcessor>(new CP())));
}
public:
CommandSelector()
{
RegisterCommand<FooCommandProcessor>("foo");
RegisterCommand<BarCommandProcessor>("bar");
// Register the rest of your commands here
}
ExitCode InvokeCommand(const std::string& command,
const std::vector<std::string>& parameters)
{
std::string lowercaseCommand;
for (int i = 0; i < int(command.size()); i++)
{
lowercaseCommand.push_back(::tolower(command[i]));
}
StringCommandProcessorMap::iterator it = _scpm.find(lowercaseCommand);
if (it == _scpm.end())
{
std::cout << "Unknown command: " << lowercaseCommand << std::endl;
return ExitCode::WRONG_USAGE;
}
return it->second->Go(parameters);
}
};
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: <your_exe_name> <command> [arguments]" << std::endl;
return int(ExitCode::WRONG_USAGE);
}
std::string command(argv[1]);
std::vector<std::string> parameters;
for (int i = 2; i < argc; i++)
{
parameters.push_back(std::string(argv[i]));
}
CommandSelector cs;
ExitCode ec = cs.InvokeCommand(command, parameters);
return int(ec);
}
You can call exec methods with the required argument to run your commands
Checkout: http://linux.die.net/man/3/exec
Check out the Command pattern:
https://en.wikipedia.org/wiki/Command_pattern
http://www.oodesign.com/command-pattern.html
Encapsulate all commands/functions in their own objects. Most probably, you don't need 200 different Command classes but only a few, grouping similar function calls with same purpose and argument count and type.
Then make a map of strings to these command objects. Command objects all have the same interface and the differences in the argument count and type of the original fnctions is encapsulated within.
A table of function calls (or similar). If speed is important, using std::unordered_map to do something like:
std::unordered_map<std::string, function> cmds;
...
cmds["mycommand"] = myCommandFunction();
I personally have written a dozen different programs with static array tables of string + function pointer as well, and just using a plain loop to iterate over the array - it's usually not the slowest part of the design [if speed matters, profile your code to see where it's taking time, then optimise, but start by writing clear and simple code, do not make the code more complex simply because you think it may be a large portion of time, before you have measured it]
An example of using std::map and function pointers [in this case lambda functions] can be found here:
https://github.com/Leporacanthicus/lacsap/blob/master/builtin.cpp#L972
Example of my comment:
#include <string>
#include <unordered_map>
#include <iostream>
typedef void(*commandPtr)(const char* args);
std::unordered_map <std::string, commandPtr> commands;
void someCommand(const char* args)
{
std::cout << "some command with args : " << args << std::endl;
}
int main()
{
commands.insert(std::make_pair("someCommand", someCommand)); // add a command to the map
std::string command, args;
std::cin >> command >> args;
if (commands.find(command) == commands.end()) // the command doesn't exist
std::cout << "Command doesn't exist";
else
commands.find(command)->second(args.c_str()); // call the command with args
std::cin.get();
return 0;
}
This allows for just one abitrary argument though.
Related
I have a class that has to process data from various files. I thought about creating one function that will read the specified file and then also accept a call back so that it can use that to process the line. Below is an example class to represent what I am trying to do:
#include <iostream>
#include <vector>
#include <string>
class Example
{
std::vector<std::string> m_exampleFileData {
"test1",
"test2",
"test3"
};
public:
void doSomethingMain(const std::string& path)
{
processFile(path, doSomething);
}
private:
void processFile(const std::string& filePath, void (Example::*fpProcessLine)(const std::string&) )
{
for (const auto& line : m_exampleFileData) {
this->*fpProcessLine(line);
}
}
void doSomething(const std::string& line)
{
std::cout << "Hello: " << line << '\n';
}
};
int main(int argc, char** argv) {
const std::string filePath{"path"};
Example ex;
ex.doSomethingMain(filePath);
}
Compiler explorer: https://godbolt.org/z/LKoXSZ
The main issue is that no matter what I do I can't seem to be able to pass the function properly to processFile. Is there a way to do this in C++? How do I go about this?
You need to spell things out explicitly, in this situation:
processFile(path, &Example::doSomething);
Furthermore, you also need to slap on an extra pair of parenthesis, due to operator precedence:
(this->*fpProcessLine)(line);
I'm putting objects in a map(code below) when i try to get it the object is empty!
Server s;
s.port = 5400;
commandsMap.insert(std::pair<string,Command>("openDataServer",s));
Server is inherent from Command
class Server: public Command{
public:
static map<string,Varinfo> symbolList;
static map<string,Command> commandsMap;
bool stop = false;
int port;
int execute(vector<string> inputs);
static int lstn(int socketfd,sockaddr_in address);
};
and here is command
class Command{
public:
Command();
int execute(vector<string> inputs);
};
and here I'm trying to find the values that I pushed up there, but the object is from class Command and its empty!
auto it = commandsMap.find(commands[index]);
if ( it != commandsMap.end() ) {
index += it->second.execute(commands);
}
note: commands[index] returns a string
and when I debug after pushing the object I see it right inside the map, but when I use find iterator it->second returns empty object Command
any ideas?
thanks
Update:
I think the problem is that the object that the map finds its not a server object, I want to push in the map many types of classes that inherts Command, and each one to run its own execute() and to have its own fields
the Command that the map returns is returned as Command Class, it should return as Server
final Question:
I want to use a shared pointer as a solution
I have classes like Server that inherits from Command, I want to put them inside a map, and then run thier own execute() as shown upthere
The problem is that you are storing your Server object as a map value of base type Command. This operation slices from Server instance all the fields and leaves only those from base class.
Usual solution to this problem is to store pointer to base class in the map instance of the bare object, and also use virtual interface. So I suggest you to make int execute(vector<string> inputs); virtual and override it in the Server derived class with its specific implementation. In the map use std::unique_ptr<Command> as the value:
https://coliru.stacked-crooked.com/a/df5fa3a97f897977
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
using namespace std;
struct Varinfo{};
struct sockaddr_in{};
class Command{
public:
Command() {}
virtual int execute(vector<string> inputs) {
std::cout << "From: Command" << std::endl;
return 0;}
};
class Server: public Command{
public:
static map<string,Varinfo> symbolList;
static map<string,Command> commandsMap;
bool stop = false;
int port;
int execute(vector<string> inputs) override {
std::cout << "From: server: port = " << port << std::endl;
return 0;}
static int lstn(int socketfd,sockaddr_in address){return 0;}
};
int main()
{
std::map<std::string, std::unique_ptr<Command>> commandsMap;
auto server_ptr = std::make_unique<Server>();
server_ptr->port = 5400;
commandsMap.emplace("openDataServer", std::move(server_ptr));
// or: commandsMap.emplace("openDataServer", std::make_unique<Server>(...));
int index = 0;
std::vector<std::string> commands = {"openDataServer"};
auto it = commandsMap.find(commands[index]);
if ( it != commandsMap.end() ) {
index += it->second->execute(commands);
}
}
So here's an interesting question, How would I make something kinda like a wrapper for cout?
I want to be able to add it into a dll so I can throw it into my programs. but the basic syntax of it should be
Mything::mesage << "I'm some text" << im_an_int << someclass << mything::endl;
or
Mything::mesageandlog << "I'm going to print to console, and to a file!" << mything::endl;
I can handle most of the internal logic but as to what I should put to even do this. kinda stumped.
Possibly make a static stream member in my class called message, then have an event fire when its written too that runs it through a method?
Idk, I looked around and found something sortA similar, but as for throwing it into a dll I'm at a loss. (How to write a function wrapper for cout that allows for expressive syntax?)
because this requires me to use extern and a variable, but how would I make it static so I can just straight call it without creating a variable?
Bit of clarification, something like this:
mydll.h
#include <iostream>
namespace mynamespace {
extern struct LogMessage{};
template <typename T>
LogMessage& operator<< (LogMessage &s, const T &x) {
SetStdHandle(STD_OUTPUT_HANDLE, GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE);
std::cout << "[IF] ";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_WHITE);
//LogTimestamp(); --ill impliment this.
std::cout << x << endl;
//writeStreamToLogfile(s); --and ill handle this.
return s;
}
}
driverprogram.h
#include <mydll.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
mynamespace::LogMessage << "Something: << std::endl;
}
expected output:
"[IF] [00:00:00] Something
You can create a struct, that has a << operator
struct OutputThing
{
template< class T >
OutputThing &operator<<( T val )
{
std::cout<<val;
return *this;
}
};
Now whenever you want to log, you will have to instance the object.
OutputThing()<<"x ="<<x;
If you want to avoid the repeated construction and destruction of the object, you can make it a singleton.
struct OutputThingSingleton
{
static OutputThingSingleton& GetThing()
{
static OutputThingSingleton OutputThing;
return OutputThing;
}
template< class T >
OutputThingSingleton &operator<<( T val )
{
std::cout<<val;
return *this;
}
private:
OutputThingSingleton()
{};
};
So the call now looks like
OutputThingSingleton::GetThing()<<"x ="<<x;
Which you could shorten using a macro.
This will work across multiple dlls, however depending on how it is used you can have multiple instances of the singleton existing. This would work fine as long as you don't want to maintain any state in your singleton. If you do need to ensure a single instance, you can compile it in its own dll. Any other binary that uses this dll will share the single instance 'owned' by the dll.
First of all, just to give fair warning, I'm pretty sure this won't work in a DLL. You want to put it into a header (as it's shown here).
Second, it's probably a little more elaborate than you were considering. In particular, it defines a multi-output stream class that works like any other stream. Essentially any normal overload of operator<< should work fine with it.
Unlike a normal stream operator, however, the output goes to multiple streams, and each line of output (on all the streams) is preceded by a prefix (currently set to the value "[FIX]", but it just uses the content of a string, so whatever you put in that string should work. A more polished/finished implementation would probably allow you to set the prefix with something like a manipulator, but this (currently) doesn't support that.
Finally, it does some variadic template trickery, so you can specify the output files as either file names or existing ostream objects, or a combination thereof (e.g., see demo main at end).
First, the header:
#ifndef LOGGER_H_INC_
#define LOGGER_H_INC_
#include <iostream>
#include <streambuf>
#include <vector>
#include <fstream>
class logger: public std::streambuf {
public:
logger(std::streambuf* s): sbuf(s) {}
~logger() { overflow('\n'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if (traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch (c) {
case '\n':
case '\r': {
prefix = "[FIX]";
buffer += c;
if (buffer.size() > 1)
sbuf->sputn(prefix.c_str(), prefix.size());
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
buffer.clear();
return rc;
}
default:
buffer += c;
return c;
}
}
std::string prefix;
std::streambuf* sbuf;
string buffer;
};
namespace multi {
class buf : public std::streambuf {
std::vector<std::streambuf *> buffers;
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
buf() {}
void attach(std::streambuf *s) { buffers.push_back(s); }
void attach(std::ofstream &s) { buffers.push_back(s.rdbuf()); }
int_type overflow(int_type c) {
bool eof = false;
for (std::streambuf *buf : buffers)
eof |= (buf->sputc(c) == traits_type::eof());
return eof ? traits_type::eof() : c;
}
};
class logstream : public std::ostream {
std::vector<std::ofstream *> streams;
buf outputs;
logger log;
void attach(std::ostream &s) { outputs.attach(s.rdbuf()); }
void attach(char const *name) {
std::ofstream *s = new std::ofstream(name);
streams.push_back(s);
outputs.attach(s->rdbuf());
}
template <typename T, typename...pack>
void attach(T &t, pack&...p) {
attach(t);
attach(p...);
}
public:
template <typename...pack>
logstream(pack&...p) : log(&outputs), std::ostream(&log) { attach(p...); }
~logstream() {
for (auto d : streams) {
d->close();
// Bug: crashes with g++ if delete is allowed to execute.
//delete d;
}
}
};
}
#endif
Then the demo of how to use it:
#include "logger"
int main(){
multi::logstream l(std::cout, "c:/path/log.txt");
l << "This is a prefixed string\n";
}
Obviously the header is fairly large, but the code to use it seems (at least to me) about as simple as you can hope for -- create an object, specifying where you want the output to go, just a normal stream -- except that you can specify more than one. Then write to it like you would to any other stream, and the output goes to all of the specified outputs, with each line preceded by the specified prefix.
I have a large series of functions that all look very similar: they take the same arguement type and return strings.
std::string f1(T arg);
std::string f2(T arg);
std::string f3(T arg);
std::string f4(T arg);
.
.
.
In a loop, they are used according to one of the variables inside the struct T. Currently to do this, I just have a large switch/case block in my code.
Is there any better coding style for doing this? The large block of code looks very weird.
I wish c++ could be like python and do eval("f" + str(i) + "(arg))"
The block is something like this:
std::string out = "";
switch (arg.tag){
case 1:
out += f1(arg);
break;
case 2:
out += f2(arg);
break;
.
.
.
}
for about 2 dozen cases
With C++11 you can do this fairly easily with std::function and a map:
#include <map>
#include <functional>
#include <string>
#include <iostream>
std::string f1(int) { return "f1"; }
std::string f2(int) { return "f2"; }
std::map<int, std::function<std::string(int)> > funcs = {
{1,f1},
{2,f2}
};
int main() {
std::cout << funcs[1](100) << "\n";
}
Without C++11 you'll want to either use Boost instead of std::function or roll your own type instead. You could use plain old function pointers but that would rule out some handy things (like std::bind/boost::bind, functor objects, lambda functions. You could also define a type hierarchy with an interface that your functions implement for example the following works in C++03 except for the way the map is initialised:
#include <map>
#include <functional>
#include <string>
#include <iostream>
std::string f1(int) { return "f1"; }
std::string f2(int) { return "f2"; }
std::map<int, std::string(*)(int)> funcs = {
std::make_pair(1,f1),
std::make_pair(2,f2)
};
int main() {
std::cout << funcs[1](100) << "\n";
}
or this which lets you write any kind of functor object you like:
#include <map>
#include <string>
#include <iostream>
struct thing {
virtual std::string operator()(int) const = 0;
};
struct f1 : thing {
std::string operator()(int) const { return "f1"; }
};
struct f2 : thing {
std::string operator()(int) const { return "f2"; }
};
// Note the leak - these never get deleted:
std::map<int, thing*> funcs = {
std::make_pair(1,new f1),
std::make_pair(2,new f2)
};
int main() {
std::cout << (*funcs[1])(100) << "\n";
}
One way to emulate the Eval() is to have a map. The key of the map would be the names of the functions, and the values would be the pointers to the corresponding functions.
In this case you will be able to call the functions needed with the map's operator[] by their name. This will somehow emulate the eval("f" + str(i) + "(arg))" behavior, though it may still not be the best solution for you.
Out of curiosity, I thought I'd try and write a basic C++ class that mimics C#'s multiple delegate pattern. The code below mostly does the job, with the nasty sacrifice of losing almost all type-safety, but having to use the initial dummy parameter to set up the va_list really seems a bit off. Is there a way to use va_list without this?
I do realize there are ways to do this with (for example) boost, but I was aiming for something dead simple that used just the standard library.
#include <vector>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <algorithm>
using namespace std;
class CDelegate
{
public:
virtual bool operator()(va_list params) = 0;
};
class CMultipleDelegateCaller
{
public:
typedef vector<CDelegate*> CDelegateVector;
CMultipleDelegateCaller& operator+=(CDelegate &rDelegate)
{
m_apDelegates.push_back(&rDelegate);
return (*this);
}
CMultipleDelegateCaller& operator-=(CDelegate &rDelegate)
{
CDelegateVector::iterator iter =
find(m_apDelegates.begin(), m_apDelegates.end(), &rDelegate);
if (m_apDelegates.end() != iter) m_apDelegates.erase(iter);
return (*this);
}
bool Call(int iDummy, ...)
{
va_list params;
CDelegate* pDelegate;
CDelegateVector::iterator iter;
for (iter = m_apDelegates.begin(); iter != m_apDelegates.end(); ++iter)
{
pDelegate = *iter;
va_start(params, iDummy);
if (!(*pDelegate)(params)) return false;
va_end(params);
}
return true;
}
private:
CDelegateVector m_apDelegates;
};
class CTestDelegate:
public CDelegate
{
public:
CTestDelegate():m_iId(++s_iCount) {}
virtual bool operator()(va_list params)
{
int iIntParam = va_arg(params, int);
char* szCharPtrParam = va_arg(params, char*);
string* psStringParam = va_arg(params, string*);
cout<<m_iId<<"{"
<<iIntParam<<", "
<<szCharPtrParam<<", "
<<*psStringParam<<"}"<<endl;
return true;
}
int m_iId;
static int s_iCount;
};
int CTestDelegate::s_iCount = 0;
int main(int argc, char* argv[])
{
CMultipleDelegateCaller cDelegateCaller;
CTestDelegate cTestDelegate1;
CTestDelegate cTestDelegate2;
cout<<"--------------------"<<endl;
cDelegateCaller += cTestDelegate1;
cDelegateCaller += cTestDelegate2;
string sString("World");
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate1;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate2;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cin>>sString;
return 0;
}
Functions with ellipsis in C++ is only for compatibility with C. Using C++ I'd return temporary helper object in Call function and add template operator% to pass variable number of arguments. To use it in the following way:
cDelegateCaller.Call() % 2 % "Hello" % sString; // dummy argument isn't required
As to your question, Standard requires to invoke va_start before any access to the unnamed arguments. And va_start requires second argument which is the identifier of the rightmost parameter in the variable parameter list in the function definition.
Out of Kirill's answer you can conclude that it's possible to create a type-safe delegate, using a template argument-combining function. This function also needs a dummy starting point, but has the benefit of type-safety.
The FastFormat library uses this, boost uses this, and I once provided another example in an answer to another question.