2015-06-01 12 views
11

La libreria di C++ 11 ha diversi generatori di numeri casuali (RNG), ognuno dei quali implementa il concetto UniformRandomNumberGenerator. Questi possono quindi essere usati come argomento per distribuzioni casuali, vedere anche this documentation per una panoramica.pacchetto (tipo cancella) un generatore di numeri casuali

Il vantaggio di questo design è che la scelta del motore RNG sottostante è disaccoppiata dalla sua applicazione. Tuttavia, il progetto richiede anche la definizione (non solo le dichiarazioni) di tutte le chiamate al RNG per essere disponibili (se il tipo RNG deve rimanere non specificato come parametro del modello). Così, in

struct complicated_random_distribution 
{ 
    /* 
    some data and auxiliary methods here 
    */ 
    // complicated; may call RNG::operator() many times 
    template<typename RNG> 
    some_type operator()(RNG&gen) const; 
}; 

l'elemento operator() non può essere direttamente implementato in un'unità di compilazione separata (CU), ma deve essere disponibile nello stesso file di intestazione (o uno #include d da esso).

Per un'implementazione separata, uno idealmente vorrebbe un modo per confezionare un RNG nello stesso modo come std::function<> confezioni qualsiasi oggetto callable. (Semplicemente usando std::function e fornendo i valori per RNG::min() e RNG::max() come argomenti a una funzione definita in una CU separata è restrittivo e non consente di utilizzare, ad esempio, std::uniform_real_distribution<> all'interno).

Come si può fare? Sono disponibili implementazioni per questo? La libreria std fornirà questo in futuro? O sono dopo un'aringa rossa?


Modifica generatori di numeri casuali sono tenuti ad avere static membri min() e max(), rendendo tipo cancellazione difficile o impossibile (libstdc di GNU ++ non fa questa ipotesi e un tipo di cancellazione con i membri non statici min() e max() funziona, ma non con libl ++ di LLVM, che utilizza lo standard richiesto per i membri static). C'è un modo per risolvere ancora questo problema? In caso contrario, ciò non implica che lo standard C++ abbia un'interfaccia mal riuscita per i generatori di numeri casuali?

+0

si può facilmente implementare che fuori linea, la definizione solo bisogno di essere nel file di intestazione. Sarebbe davvero così brutto? –

+1

Il termine che stai cercando è "cancella tipo", non "pacco". Inoltre, come gestiresti 'min()' e 'max()'? Tutti gli URNG hanno la stessa gamma? Presumo di no? – Barry

+0

@Walter Puoi sicuramente: http://coliru.stacked-crooked.com/a/47941423fc589739 Beh, forse stiamo parlando di cose diverse. –

risposta

2

Adattare il RNG con independent_bits_engine e digitare cancellare il RNG adattato. Hai piena conoscenza di ciò che sono min() e max() di independent_bits_engine.

Ecco uno schizzo:

struct RNG_wrapper { 
    using result_type = std::uint32_t; 
    static constexpr result_type min() { return 0; } 
    static constexpr result_type max() { return 0xFFFFFFFF; } 

    template<class RNG> 
    using my_engine_type = std::independent_bits_engine<RNG, 32, result_type>; 

    template<class RNG, 
      class = std::enable_if_t<!std::is_same<std::decay_t<RNG>, RNG_wrapper>{}>> 
    RNG_wrapper(RNG&& r) 
     : rng(my_engine_type<std::decay_t<RNG>>(std::forward<RNG>(r))) {} 

    result_type operator()() { return rng(); } 
    std::function<result_type()> rng; 
}; 
+0

Ok ora capisco l'idea: usando un 'independent_bits_engine' si possono rendere statici' min' e 'max', perché dipendono solo dal numero statico di bit .. intelligente! – Walter

1

Questo funziona in clang e gcc (con libstdC++), ma questo non è rigorosamente uno , per il motivo noto che min e max non sono statici.

#include <cassert> 
#include <random> 
#include <functional> 
#include <iostream> 

template<typename T> 
class AnyUniformRandomNumberGenerator 
{ 
    T mMin; 
    T mMax; 
    std::function<T()> mValue; 
public: 

    using result_type = T; 

    template<typename UniformRandomNumberGenerator> 
    AnyUniformRandomNumberGenerator(UniformRandomNumberGenerator uniformRandomNumberGenerator) : 
    mMin(UniformRandomNumberGenerator::min()), 
    mMax(UniformRandomNumberGenerator::max()), 
    mValue([=]() mutable { return uniformRandomNumberGenerator(); }) 
    {} 

    T operator()() 
    { 
     return mValue(); 
    } 

    T min() 
    { 
     return mMin; 
    } 

    T max() 
    { 
     return mMax; 
    } 
}; 

int main() 
{ 
    std::default_random_engine rng; 
    AnyUniformRandomNumberGenerator<decltype(rng())> any{rng}; 

    assert(any() <= any.max()); 
    assert(any() >= any.min()); 

    std::uniform_int_distribution<> dist{1, 6}; 

    std::cout << dist(any); 
} 

GCC: http://rextester.com/ANAP79935

clang http://rextester.com/YCIIR21607

+0

@Walter È una cosa di libstdC++ che penso. Se cambi in libstdC++ in apple clang suppongo che funzionerà. – tahsmith

+1

@Walter Penso che rextester usi anche libstdC++ con Clang. –

+0

Questo è essenzialmente ciò che ho provato inizialmente, ma cosa non viene compilato con 'clang ++ -stdlib = libC++ -std = C++ 11'. L'uso di 'libstdC++' ha funzionato, ma non è conforme allo standard. – Walter

Problemi correlati