首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何创建异构对象的集合

如何创建异构对象的集合
EN

Stack Overflow用户
提问于 2018-02-24 06:25:51
回答 3查看 554关注 0票数 1

我想创建一个异构对象的集合;即。不同类型的对象。

当这些对象具有类似的功能(包括成员),但不从同一个父类派生时,这将是有用的。

一个很好的例子是随机数引擎:minstd_randmt19937ranlux24都是引擎。它们具有相同的成员(如call operator ()),但它们不是从公共的"Engine“类派生出来的,因此具有不同的类型。

随机数分布的情况也是如此。

如果有一个常见的根类“Engine”,我可以很容易地创建这些对象的向量,如下所示:

代码语言:javascript
复制
vector<Engine> engines {minstd_rand, mt19937, ranlux24};

这样,我就可以在循环中调用一个函数,如下所示:

代码语言:javascript
复制
/// 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
}

但是,我不能这么做。

如果我使用一个元组来包装每个引擎,那么每个对象都有一个不同的类型:

代码语言:javascript
复制
tuple<type1>, tuple<type2>, .... 

同样,类型将是异构的,我无法创建它们的集合。

因此,问题是,是否有可能创建一个异构对象的集合,如果有,如何创建?

EN

回答 3

Stack Overflow用户

发布于 2018-02-24 06:45:16

您可以使用vector<function<size_t ()>>来保存这些引擎。

代码语言:javascript
复制
using Engine = function<size_t ()>;
vector<Engine> engines = {minstd_rand{}, mt19937{}, ranlux24{}};
for (auto &e : engines) {
    cout << e() << endl;
}
票数 2
EN

Stack Overflow用户

发布于 2018-02-24 16:58:22

您只需创建您自己的多态层次结构,就可以将不同类型的伪随机数生成器封装在其中。不同的标准生成器有一个公共接口,即使它们不是从公共基类型派生出来的,这使得这一点变得更容易了。

有点像这样:

代码语言:javascript
复制
// 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';
}
票数 1
EN

Stack Overflow用户

发布于 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

代码语言:javascript
复制
#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)事实上,我们所做的工作如下:

代码语言:javascript
复制
a) The heterogeneous engines are abstracted by the parameterized sub-class **RndSub**. Each sub-class is different.
代码语言:javascript
复制
b) However, they now have a single common base-class **RndBase**.
代码语言:javascript
复制
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.
代码语言:javascript
复制
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.

这个解是专门针对随机数的。我试图为任何类(具有类似接口的类)提供解决方案。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48960021

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档