Is it possible to retrieve a list of child objects (of a cetain type) of an object ?
For example in this code I have an App with several available Commands. A function print all availible commands this way the user knows what he can do.
I want to iterate over each object of type Command found in App to print his doc, this way the doc updates itself automatically every time a Command is added in App.
class Command {
public:
std::string Name;
std::string Description;
virtual void Compute() = 0;
};
class StartCommand : public Command {
std::string Name = "start";
std::string Description = "Start the process";
virtual void Compute() {
// Code to start the process
}
};
class StopCommand : public Command {
std::string Name = "stop";
std::string Description = "Stop the process";
virtual void Compute() {
// Code to stop the process
}
};
class App {
public:
StartCommand StartCommand;
StopCommand StopCommand;
void PrintAvailibleCommands() {
std::cout << "All availible commands are: " << std::endl;
for (Command command : this.GetObjects<Command>()) {
std::cout << command.Name << ": " << command.Description << std::endl;
}
}
};
It's the this.GetObjects<Command>()
function which does not exist and which I would like to implement.
Do you have an idea ?
CodePudding user response:
This may solve your problem.
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
class Command {
public:
std::string Name;
std::string Description;
Command(std::string Name, std::string Description)
: Name(Name), Description(Description) {}
virtual void Compute() = 0;
};
class StartCommand : public Command {
public:
StartCommand() : Command("start", "Start the process") {}
virtual void Compute() {
// Code to start the process
}
};
class StopCommand : public Command {
public:
StopCommand() : Command("stop", "Stop the process") {}
virtual void Compute() {
// Code to stop the process
}
};
class App {
public:
template <typename T> void regCommand() { commands.push_back(new T); }
App() {
regCommand<StartCommand>();
regCommand<StopCommand>();
}
vector<Command *> commands;
void PrintAvailableCommands() {
std::cout << "All available commands are: " << std::endl;
for (Command *command : commands) {
std::cout << command->Name << ": " << command->Description
<< std::endl;
}
}
};
int main() {
App app;
app.PrintAvailableCommands();
return 0;
}
CodePudding user response:
Often, I find it easier to put something into a collection directly when I want it to be there at some point.
#include <iostream>
#include <tuple>
#include <string>
struct Command {
std::string Name;
std::string Description;
virtual void Compute() = 0;
};
struct StartCommand : Command {
std::string Name = "start";
std::string Description = "Start the process";
virtual void Compute() {
// Code to start the process
}
};
struct StopCommand : Command {
std::string Name = "stop";
std::string Description = "Stop the process";
virtual void Compute() {
// Code to stop the process
}
};
struct App {
std::tuple<StartCommand, StopCommand> commands{};
template<class Cmd>
static void PrintCommand(const Cmd &cmd) {
std::cout << cmd.Name << ": " << cmd.Description << std::endl;
}
void PrintAvailibleCommands() {
std::cout << "All available commands are: " << std::endl;
std::apply([](const auto &...cmds) { (PrintCommand(cmds), ...); }, commands);
}
};