Question

Je génère des valeurs aléatoires avec de nouveaux générateurs et distributions C++11.Dans une fonction, cela fonctionne à merveille et ressemble à ceci :

void foo() {
   mt19937 generator;
   uniform_int_distribution<unsigned> distribution;
   auto dice = bind(distribution, generator);
   // dice() will now give a random unsigned value
}

Mais comment puis-je placer les trois objets dans une classe en tant que données membres ?je peux simplement écrire generator et distribution en tant que membres de données, mais comment puis-je faire dice un membre de données sans connaître (ou vouloir connaître) son type exact ?Étonnamment, ceci

class X {
   mt19937 generator;
   uniform_int_distribution<unsigned> distribution;
   decltype(bind(distribution, generator)) dice;
};

donne l'erreur error C2660: 'bind' : function does not take 2 arguments dans Visual Studio 2013.

Était-ce utile?

La solution

Tu pourrais toujours haleter écrivez une fonction au lieu d'utiliser un lambda/bind/etc. :

class X {
   mt19937 generator;
   uniform_int_distribution<unsigned> distribution;
public:
   auto dice() -> decltype(distribution(generator)) {
     return distribution(generator);
   }
   // or alternatively
   auto operator() () -> decltype(distribution(generator)) {
     return distribution(generator);
   }
};

Points bonus pour le paramétrage sur le type de générateur et/ou de distribution, et pour le maintien du générateur avec un std::shared_ptr afin que vous puissiez créer plusieurs objets avec des distributions différentes partageant le même moteur.Vous souhaiterez éventuellement qu'un constructeur amorce également le générateur - Idéalement avec quelque chose comme std::random_device{}().

Ou, la réponse que je pense que tu cherches:

class X {
   mt19937 generator{std::random_device{}()};
   uniform_int_distribution<unsigned> distribution{1,6};
public:
   decltype(bind(std::ref(distribution), std::ref(generator))) dice{
     bind(std::ref(distribution), std::ref(generator))
   };
};

Je suis désolé de m'être moqué de toi pour avoir essayé d'utiliser bind en premier lieu :c'est en fait plutôt sympa que vous puissiez écrire cette classe sans "aucun code" en C++11.Nous devons obtenir une inférence de type pour les déclarations de membres de classe en C++17, cela pourrait donc être :

class X {
   auto generator = mt19937{std::random_device{}()};
   auto distribution = uniform_int_distribution<unsigned>{1,6};
public:
   auto dice = bind(std::ref(distribution), std::ref(generator));
};

Étant donné que le dernier article Concepts Lite propose d'utiliser des noms de concepts n'importe où dans la langue où auto peut sembler signifier « déduire un type, mal formé si le type ne modélise pas le concept nommé », auto les déclarations des membres ne sont peut-être pas hors de question.

Autres conseils

Cela fonctionne sur GCC.Je suis presque sûr que c'est juste un bug du compilateur.Malheureusement, cela signifie que vous devez mordre la pilule amère et utiliser l'une des solutions de contournement décrites dans les autres réponses.

Le résultat de std::bind n'est pas précisé :cela signifie que vous ne pouvez pas stocker son résultat brut sans inférence de type.Cependant, vous pouvez utiliser std::function pour encapsuler le résultat de bind:

#include <functional>
std::function<unsigned()> dice(std::bind(distribution, generator));
auto result = dice();

MODIFIER: Comme celui qui l'a dit ci-dessus, il s'agit clairement d'un problème avec Visual Studio.Je peux confirmer que cela compile avec VS2013 :

#include <functional>
#include <random>

using namespace std;

class X {
    mt19937 generator;
    uniform_int_distribution<unsigned> distribution;
    std::function<unsigned()> dice;

public:
    X() : dice(bind(distribution, generator)) {}

    unsigned roll() { return dice(); }
};

mais en changeant le type de dice à decltype(bind(distribution, generator)) fait échouer le tout avec brio (même si cela fonctionne toujours avec clang).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top