我可以在没有模板变量的情况下将随机引擎分配给变量吗?

时间:2016-03-14 17:17:24

标签: c++ random

我想将随机引擎分配给变量。

基本原因:我希望能够在测试和生产代码之间切换随机引擎。测试应使用比生产代码更可预测的随机生成器。

使用下面的示例代码可行,但我必须将<T>拖到我不想要的所有代码中。

#include <random>
#include <iostream>

class MyEngine {
public:
    typedef int result_type;

    result_type operator()() {
        return 42;
    }

    constexpr result_type min() {
        return 0;
    }

    constexpr result_type max() {
        return 100;
    }
};

template <class T>
struct EngineHolder {
    T engine;

    EngineHolder(const T& engine) : engine(engine) { }
};


//template <class T>
void doSomeWork(EngineHolder/*<T>*/* engineHolder) {
    std::uniform_int_distribution<int> distribution(30, 50);

    for (int i = 0; i < 50; i++) {
        int v = distribution(engineHolder->engine);
        std::cout << v << " ";
    }
    std::cout << std::endl;
}


int main() {
    // Engine 1
    std::default_random_engine engine1;
    EngineHolder<std::default_random_engine> foo1(engine1);
    doSomeWork(&foo1);

    // Engine 2
    std::default_random_engine engine2(145457);
    EngineHolder<std::default_random_engine> foo2(engine2);
    doSomeWork(&foo2);

    // Engine 3
    std::linear_congruential_engine<unsigned int, 1, 1, 10> engine3;
    EngineHolder<std::linear_congruential_engine<unsigned int, 1, 1, 10>> foo3(engine3);
    doSomeWork(&foo3);

    // My Engine
    MyEngine myEngine;
    EngineHolder<MyEngine> foo4(myEngine);
    doSomeWork(&foo4);

    return 0;
}

我想通过定义一个要使用哪个引擎的宏来让预处理器完成这个任务 现在我想知道还有另一种方式吗?

2 个答案:

答案 0 :(得分:2)

看起来你想要一种方法将任何类型的随机数生成器传递给Collectors.counting()。如果是这种情况,我只需将函数模板化为

doSomeWork

然后你可以像

一样使用它
template <class Engine>
void doSomeWork(Engine engine) {
    std::uniform_int_distribution<int> distribution(30, 50);

    for (int i = 0; i < 50; i++) {
        int v = distribution(engine);
        std::cout << v << " ";
    }
    std::cout << std::endl;
}

Live Example

现在您根本不需要指定模板类型。

答案 1 :(得分:2)

uniform_int_distribution::operator()的调用对参数的要求很少,详细信息为UniformRandomNumberGenerator。它必须提供成员result_typemin()max()operator()()。您已经使用模板类完成了这项工作。

您可以创建包含这些方法的接口,并将该接口传递到doSomeWork而无需模板。具体的EngineHolder类将从接口派生。唯一的限制是您不能创建typedef虚拟,因此所有派生类必须使用相同的result_type

class EngineHolderInterface {
public:
    typedef int result_type;

    virtual ~EngineHolderInterface() {};
    virtual result_type operator()() = 0;
    virtual result_type min() = 0;
    virtual result_type max() = 0;
};


template <class T>
struct EngineHolder : public EngineHolderInterface {
    T engine;

    EngineHolder(const T& engine) : engine(engine) { }
    virtual result_type operator()() { return engine(); }
    virtual result_type min() { return engine.min(); }
    virtual result_type max() { return engine.max(); }
};

void doSomeWork(EngineHolderInterface* engineHolder) {
    std::uniform_int_distribution<int> distribution(30, 50);

    for (int i = 0; i < 50; i++) {
        int v = distribution(*engineHolder);
        std::cout << v << " ";
    }
    std::cout << std::endl;
}