Standard way is to make option1 and option2 derived classes from a base_class which seems consistent with your sample main(). Using a generic Factory class template, here is an example:
#include <functional>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option1." << std::endl;
}
};
class option2 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option2." << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, []() { return std::make_unique<option1>(); } }
, { 2, []() { return std::make_unique<option2>(); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store(1, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
This compiled for me on linux using g++ -std=c++17 main.cc.
There are improvements that can be made to this code, but I copied your main() function in order to illustrate the basic idea(s). Hope that helps.
Edit 21 Sept 2018 - Example of how to pass parameters into constructors.
File: factory.h
#pragma once
#include <functional>
#include <memory>
#include <unordered_map>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
File: main.cc
#include "factory.h"
#include <iostream>
#include <string>
#include <vector>
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
const double mD;
public:
option1(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option1: mD("<<mD<<')' << std::endl;
}
};
class option2 : public base_class
{
const double mD;
public:
option2(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option2: mD("<<mD<<')' << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class,double>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, [](double d) { return std::make_unique<option1>(d); } }
, { 2, [](double d) { return std::make_unique<option2>(d); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel,static_cast<double>(i)));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store1(1, n_iterations);
storage_class store2(2, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store1.my_store[i]->create_data();
store2.my_store[i]->create_data();
}
}
Output:
I'm option1: mD(0)
I'm option2: mD(0)
I'm option1: mD(1)
I'm option2: mD(1)
I'm option1: mD(2)
I'm option2: mD(2)
I'm option1: mD(3)
I'm option2: mD(3)