I have a std::vector<>
of pointers to a base functor. This container, a calculator class, should be able to hold onto an arbitrary number of these function objects that calculate arbitrary statistics.
The part I'm struggling with is how to write a method for the container class, that iterates over these pointers, picks the one you're interested in out of hte group, tells it to do its job by calling operator()
, then returns the result.
Here's some code that illustrates the idea:
#include <iostream>
#include <memory> //shared_ptr
#include <vector>
class BaseFunctor{
virtual double operator()(std::vector<double> inputs) = 0;
};
class Sum : public BaseFunctor{
double operator() (std::vector<double> inputs){
double sum (0.0);
for(auto elem : inputs)
sum += elem;
return sum;
}
};
class Prod : public BaseFunctor{
double operator() (std::vector<double> inputs){
double sum (1.0);
for(auto elem : inputs)
sum *= elem;
return sum;
}
};
class Calculator {
private:
std::vector<std::shared_ptr<BaseFunctor>> m_stats;
std::vector<double> m_simple_data;
public:
Calculator()
: m_simple_data({1.0, 2.0, 3.0}) {};
void addStat(std::shared_ptr<BaseFunctor> stat) {
m_stats.push_back(stat);
}
// calculate stat?
};
int main() {
Calculator calc;
calc.addStat(std::make_shared<Sum>());
calc.addStat(std::make_shared<Prod>());
return 0;
}
Now, how could I tell calc
to give me the product, and only the product? Especially when I can't control what statistics the user ends up being interested in?
I imagine I could store the pointers in a map
, instead, but that seems redundant: making the key have the same name as the class.
Here is an idea, but it doesn't compile.
This works, but I'm open to comments/criticisms/suggestions.
#include <iostream>
#include <memory> //unique_ptr
#include <map>
#include <vector>
#include <string>
#include <functional>
class BaseFunctor{
public:
virtual double operator()(std::vector<double> inputs) = 0;
virtual std::string name() = 0;
};
class Sum : public BaseFunctor{
double operator() (std::vector<double> inputs){
double sum (0.0);
for(auto elem : inputs)
sum += elem;
return sum;
}
std::string name() { return "sum"; }
};
class Prod : public BaseFunctor{
double operator() (std::vector<double> inputs){
double prod (1.0);
for(auto elem : inputs)
prod *= elem;
return prod;
}
std::string name() { return "prod"; }
};
class Calculator {
private:
std::map<std::string, std::unique_ptr<BaseFunctor> > m_stats;
std::vector<double> m_simple_data;
public:
Calculator()
: m_simple_data({1.0, 2.0, 5.0}) {};
void addStat(std::unique_ptr<BaseFunctor> stat) {
m_stats.insert(
std::pair<std::string, std::unique_ptr<BaseFunctor>>(
stat->name(),
std::move(stat)
)
);
//m_stats.push_back(std::move(stat));
}
double calc(std::string op_name){
return (*m_stats[op_name])(m_simple_data);
}
};
int main() {
Calculator thing;
thing.addStat(std::unique_ptr<BaseFunctor>(new Sum()) );
thing.addStat(std::unique_ptr<BaseFunctor>(new Prod()) );
std::cout << "sum: " << thing.calc("sum") << "\n";
std::cout << "prod: " << thing.calc("prod");
return 0;
}