Pregunta

Estoy generando valores aleatorios con nuevos generadores y distribuciones de C++ 11.En una función funciona de maravilla y se ve así:

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

Pero, ¿cómo puedo poner los tres objetos de una clase como miembros de datos?puedo simplemente escribir generator y distribution como miembros de datos, pero ¿cómo hago? dice ¿Un miembro de datos sin saber (o querer saber) su tipo exacto?Sorprendentemente esto

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

produce el error error C2660: 'bind' : function does not take 2 arguments en Visual Studio 2013.

¿Fue útil?

Solución

siempre podrías jadear escriba una función en lugar de usar 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);
   }
};

Puntos de bonificación por parametrizar el tipo de generador y/o distribución, y por sujetar el generador con un std::shared_ptr para que puedas hacer varios objetos con diferentes distribuciones que compartan el mismo motor.Eventualmente querrás que un constructor también inicie el generador; idealmente con algo como std::random_device{}().

O, la respuesta que creo que estás buscando:

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))
   };
};

Lamento haberme burlado de ti por intentar usar bind en primer lugar:En realidad, es genial que puedas escribir esta clase "sin código" en C++11.Necesitamos obtener inferencia de tipos para las declaraciones de miembros de clase en C++ 17, por lo que esto podría ser:

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));
};

Dado que el último artículo de Concepts Lite propone utilizar nombres de conceptos en cualquier parte del idioma donde auto puede parecer que significa "inferir un tipo, mal formado si el tipo no modela el concepto con nombre". auto Las declaraciones de los miembros pueden no estar fuera de discusión.

Otros consejos

Funciona en GCC.Estoy bastante seguro de que es sólo un error del compilador.Desafortunadamente, esto significa que debe tomar la píldora amarga y utilizar una de las soluciones descritas en las otras respuestas.

El resultado de std::bind no está especificado:esto significa que no puede almacenar su resultado sin procesar sin inferencia de tipos.Sin embargo, puedes utilizar std::function para encapsular el resultado de bind:

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

EDITAR: Como quien dijo anteriormente, esto es claramente un problema de Visual Studio.Puedo confirmar que esto se compila con 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(); }
};

pero cambiando el tipo de dice a decltype(bind(distribution, generator)) hace que todo falle con gran éxito (aunque todavía funciona con sonido metálico).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top