How to adapt static polymorphic classes to dynamic polymorphic behavior?
Dear all,
I have problems in mixing static and dynamic polymorphism.
I need dynamic polymorphism in order to create "heterogeneous"
containers (e.g., std::vector<base*>).
Specifically, I have some "untouchable classes" (i.e., coming from
third party libraries) which represent
* random number generators
--- [code] ---
template <typename IntT, IntT a, IntT c, IntT m>
class linear_congruential
{
IntT operator()() {....} // Generate a random number
};
template <typename UIntT, size_t w, size_t n, size_t m, size_t r,
UIntT a, size_t u, size_t s, UIntT b, size_t t, UIntT c, size_t l>
class mersenne_twister
{
IntT operator()() {....} // Generate a random number
};
--- [/code] ---
* probability distributions
--- [code] ---
template <typename RealT>
class exponential {...};
template <typename RealT, typename GeneratorT>
RealT rand(exponential<RealT> const& d, GeneratorT& g) {...}
template <typename RealT>
class normal {...};
template <typename RealT, typename GeneratorT>
RealT rand(normal<RealT> const& d, GeneratorT& g) {...}
--- [/code] ---
Now since I need both to store different probability distributions
inside a vector and to decide what distribution to use at run-time,
I'm trying to create a set of adaptor and base classes in order to get
dynamic polymorphism.
Something like this:
--- [code] ---
namespace my {
template <typename RealT> class base_distribution {...};
template <typename DistributionT> class distribution_adaptor: public
base_distribution<typename DistributionT::real_type> {...};
} // Namespace my
int main() {
//...
std::vector<my::base_distribution<double>*> distrs;
distrs.push_back( new distribution_adaptor<normal>(normal(0,1)) );
distrs.push_back( new distribution_adaptor<exponential>(exponential
(1)) );
}
--- [/code] ---
The problem is how to glue with the "rand" free function during the
iteration of distrs vector?
Since "virtual template methods" are not allowed, a possible solution
might be to bind the random generator to the definition of the
base_distribution class (and of the distribution_adaptor as well):
--- [code] ---
namespace my {
//...
template <typename RealT, typename GeneratorT>
class base_distribution
{
virtual RealT rand(GeneratorT& rng) = 0;
};
template <typename DistributionT, typename GeneratorT>
class distribution_adaptor: public base_distribution<typename
DistributionT::real_type, GeneratorT>
{
typedef DistributionT distr_type;
typedef typename distr_type::real_type real_type;
real_type rand(GeneratorT& rng) { return ::my::rand(rng); }
};
} // Namespace my
int main()
{
//...
typedef linear_congruential<...> generator_type:
std::vector<my::base_distribution<double,generator_type>*> distrs;
distrs.push_back( new distribution_adaptor<normal,generator_type>
(normal(0,1)) );
distrs.push_back( new distribution_adaptor<exponential,generator_type>
(exponential(1)) );
generator_type rng(123456);
for (
std::vector<my::base_distribution<double,generator_type>*>::iterator
it = distrs.begin();
it != distrs.end();
++it
) {
(*it)->rand(rng);
}
--- [/code] ---
However this solution is very bad to me since it bind the random
generator to the design of the probability distribution; furthermore,
it does not allow to choose the random generator at run-time (actually
not needed, but maybe in the future)
So, do you have a more effective way to solve this problem?
Thank you very much in advance!!
NOTE: if you want I post the entire source code. I didn't do it since
this post is already very long.
Best Regards,
-- Marco
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]