Search code examples
c++visual-studio-2010boostrandomtr1

Initializing boost::random::discrete_distribution in VC2010


I am trying to implement one of the first examples from boost::random documentation in Visual Studio 2010 SP1, using the native library (TR1).

Before when using the library, I found out that I can just use the built in VC2010 random functions and they work just like the boost ones, but here I cannot use the native functions.

The problem is with initializing discrete_distribution<> in VC2010. In Boost it takes an array:

double probabilities[] =
{
    0.5, 0.1, 0.1, 0.1, 0.1, 0.1
};
boost::random::discrete_distribution<> dist( probabilities );

But in VC2010 I don't know what I should supply it with. Here is the error I receive at compiling:

Reason: cannot convert from 'double [6]' to 'const std::tr1::discrete_distribution<>::param_type'

No constructor could take the source type, or constructor overload resolution was ambiguous

I thought that as these functions are implemented in VC2010 I can just use the built in ones while preserving multi-platform compatibility, but it seems I have to fall back on using the boost classes.

Are there any performance penalties for using boost::random over the built in class in VC2010?

Is it generally a recommended idea to stick with Boost libraries, even if they are implemented in most of the C++ compilers now?

Here are two pastebins of the working and the non-working code:

Non-working modified example using std

Working original example using boost::random

Also, what does this line means on the boost doc page?

Tip If your compiler supports std::initializer_list, you can initialize discrete_distribution directly with the weights.


Solution

  • The VC2010's std::tr1::discrete_distribution doesn't conform to the latest C++11 spec (hence the namespace tr1), and doesn't yet provide all the ways to construct it. In matter of fact, it seems that the only way to construct it in VC2010 is by either default-initializing it, or by providing a generator that gets called N times: http://msdn.microsoft.com/en-us/library/ee462277.aspx

    The constructor that takes const param_type& is essentially the same thing: http://msdn.microsoft.com/en-us/library/ee462364.aspx

    In the actual C++11 specification, there are two more overloads for the constructor of discrete_distribution, namely one that takes two input iterators, and one that takes a std::initializer_list, which brings us to your second question.

    Tip If your compiler supports std::initializer_list, you can initialize discrete_distribution directly with the weights.

    std::initializer_list is a new C++11 feature, that basically allows you to initialize not only arrays and POD structs with an initializer list, but also more complex class types by having constructors take a std::initializer_list (they can also be used for other purposes than initializing new objects though). The Wikipedia entry has more information, and the idea is quite straight-forward so I won't go into more detail here. But basically it means that instead of doing:

    double probabilities[] =
    {
        0.5, 0.1, 0.1, 0.1, 0.1, 0.1
    };
    boost::random::discrete_distribution<> dist( probabilities );
    

    You can just do:

    boost::random::discrete_distribution<> dist( {0.5, 0.1, 0.1, 0.1, 0.1, 0.1} );
    

    The construct inside the constructor parameter list constructs a std::initializer_list<double> and then passes it to the boost::random::discrete_distribution<> constructor.

    The reason why VC2010 doesn't support this yet is simply because VC2010 does not support std::initializer_list yet (it only has partial C++11 support).

    That all being said, the current implementation of VC2010's std::tr1::discrete_distribution seems to be pretty lacking, and the only way to initialize it seems to be via a generator function, so I would stick to the boost version myself.

    Even assuming you were using a compiler that fully conforms to the C++11 specification, Boost still has a lot to offer. In no way does C++11 offer everything that boost has to offer you, and there's no reason to ditch boost completely when using C++11. However if you are writing C++11 code it obviously makes sense to use the C++11 equivalents of the facilities that it does offer over the boost versions as they may have vendor specific optimizations.

    Many people still choose C++03 over C++11, since it'll be quite some time until C++11 is fully supported by all the major compiler manufacturers, so in cases like this the boost equivalents of the facilities that C++11 also offers you are still quite useful.