我想创建一个异构对象的集合;即。不同类型的对象。
当这些对象具有类似的功能(包括成员),但不从同一个父类派生时,这将是有用的。
一个很好的例子是随机数引擎:minstd_rand、mt19937和ranlux24都是引擎。它们具有相同的成员(如call operator ()),但它们不是从公共的"Engine“类派生出来的,因此具有不同的类型。
随机数分布的情况也是如此。
如果有一个常见的根类“Engine”,我可以很容易地创建这些对象的向量,如下所示:
vector<Engine> engines {minstd_rand, mt19937, ranlux24};这样,我就可以在循环中调用一个函数,如下所示:
/// Generate 10 random numbers.
void gen(vector<Engine>& engines)
{
for (auto& e : engines)
for (int i = 0; i < 10; i++)
cout << e() << endl;
}
int main()
{
gen(engines); /// Invocation
}但是,我不能这么做。
如果我使用一个元组来包装每个引擎,那么每个对象都有一个不同的类型:
tuple<type1>, tuple<type2>, .... 同样,类型将是异构的,我无法创建它们的集合。
因此,问题是,是否有可能创建一个异构对象的集合,如果有,如何创建?
发布于 2018-02-24 06:45:16
您可以使用vector<function<size_t ()>>来保存这些引擎。
using Engine = function<size_t ()>;
vector<Engine> engines = {minstd_rand{}, mt19937{}, ranlux24{}};
for (auto &e : engines) {
cout << e() << endl;
}发布于 2018-02-24 16:58:22
您只需创建您自己的多态层次结构,就可以将不同类型的伪随机数生成器封装在其中。不同的标准生成器有一个公共接口,即使它们不是从公共基类型派生出来的,这使得这一点变得更容易了。
有点像这样:
// Base interface class
class prng
{
public:
using dist_type = std::uniform_int_distribution<int>;
virtual ~prng() = default;
virtual int operator()(int min, int max) = 0;
protected:
dist_type dist;
template<typename PRNG>
static PRNG& eng()
{
thread_local static PRNG eng{std::random_device{}()};
return eng;
}
};
// smart pointers because polymorphism
using prng_uptr = std::unique_ptr<prng>;
// Generic class takes advantage of the different PRNG's
// similar interfaces
template<typename PRNG>
class typed_prng
: public prng
{
public:
int operator()(int min, int max) override
{ return dist(eng<PRNG>(), dist_type::param_type(min, max)); }
};
// Some nice names
using prng_minstd_rand = typed_prng<std::minstd_rand>;
using prng_mt19937 = typed_prng<std::mt19937>;
using prng_ranlux24 = typed_prng<std::ranlux24>;
int main()
{
// A vector of smart base pointers to typed instances
std::vector<prng_uptr> prngs;
// Add whatever generators you want
prngs.push_back(std::make_unique<prng_minstd_rand>());
prngs.push_back(std::make_unique<prng_mt19937>());
prngs.push_back(std::make_unique<prng_ranlux24>());
// numbers between 10 and 50
for(auto const& prng: prngs)
std::cout << (*prng)(10, 50) << '\n';
}发布于 2018-02-26 16:48:17
ver 1@Galik的文章有效地展示了创建多态层次结构的基本技术,我将在下面对此进行解释。
这篇文章旨在演示(而不是实现)所涉及的技术。因此,它不编译:http://coliru.stacked-crooked.com/a/0465c2a11d3a0558
我已经更正了基本问题,下面的版本是第2版。
http://coliru.stacked-crooked.com/a/9bb0f47251e6dfed
所涉及的技术是重要的。我投票赞成@Galik的职位。
但是,@Galik的解决方案有一个问题: random_device()引擎是在基类本身中硬编码的。因此,无论哪个引擎在子类中作为参数传递,它总是被使用。事实上,作为参数传递给子类的引擎应该被用作随机数的来源。
我已经更正了这一点,并在以下版本3中更改了一些名称:http://coliru.stacked-crooked.com/a/350eadb55a4bafe7
#include <vector>
#include <memory> /// unique_ptr
#include <random>
#include <iostream>
/// Declarations ...
class RndBase; /// Random number base class
/// Generic Random number sub-class
/// takes advantage of the different Engines' similar interfaces
template<typename Eng>
class RndSub;
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args);
/// Implementation ...
/// Random number base class
class RndBase
{
public:
using dist_type = std::uniform_int_distribution<int>;
virtual ~RndBase() = default;
virtual int operator() (int min, int max) = 0;
protected:
dist_type dist;
/// factory method
template<typename Eng>
static Eng& eng()
{
static Eng eng {Eng {}};
return eng;
}
}; // RndBase
/// Generic Random number sub-class
/// takes advantage of the different Engines' similar interfaces
template<typename Eng>
class RndSub : public RndBase
{
public:
/// Generate a random number.
int operator() (int min, int max) override
{
return dist(eng<Eng>(), dist_type::param_type(min, max));
}
};
int main()
{
using Eminstd_rand = RndSub<std::minstd_rand>;
using Emt19937 = RndSub<std::mt19937>;
using Eranlux24 = RndSub<std::ranlux24>;
/// smart pointers because of polymorphism
using pRndBase = std::unique_ptr<RndBase>;
/// A vector of smart base pointers to typed sub-classes
std::vector<pRndBase> prndbases;
/// Add whatever generators you want
prndbases.push_back(make_unique<Eminstd_rand> ());
prndbases.push_back(make_unique<Emt19937> ());
prndbases.push_back(make_unique<Eranlux24> ());
/// random numbers between 10 and 50
for(auto const& prb : prndbases)
std::cout << (*prb) (10, 50) << std::endl;
}
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T> {new T {args...}};
} // make_unique()对“多态层次”模式的解释如下:
1)我们知道所有的发动机都有不同的类型,尽管接口是相同的。
2)我们创建了一个抽象基类(RndBase),其中包含了这个接口。它还定义了一个名为eng()的参数化(静态)工厂方法,它创建参数Eng的一个对象并返回对它的引用。预计发动机将被用作参数。
3)我们创建了一个名为RndSub的参数化子类,它是从基类RndBase派生的。这个类定义了一个调用操作符,它返回通过调用分布获得的随机数。
4)事实上,我们所做的工作如下:
a) The heterogeneous engines are abstracted by the parameterized sub-class **RndSub**. Each sub-class is different.b) However, they now have a single common base-class **RndBase**.c) Since there is only a single base class (**RndBase**), we can now create a `vector<RndBase>`, which is homogeneous. The sub-classes of **RndBase** are heterogeneous.d) Since the interface is common, we can use the interface defined in the base class to invoke the implementation in the sub-class. This implementation invokes the factory method **eng**() in the base class to obtain an engine, which is passed as argument to the distribution. This returns the random number.这个解是专门针对随机数的。我试图为任何类(具有类似接口的类)提供解决方案。
https://stackoverflow.com/questions/48960021
复制相似问题