#include <cassert>
#include <cstdlib>
#include <array>
#include <iostream>
#include <numeric>
#include <utility>
// Wraps a std::array of TKey/TValue pairs and provides a method
// to randomly select a TKey with TValue bias.
template< typename TKey, typename TValue, std::size_t TSize >
class weights final
{
public:
using pair = const std::pair< const TKey, const TValue >;
using array = const std::array< pair, TSize >;
weights( array values )
: values_{ values }
, sum_{ std::accumulate(values_.begin(), values_.end(), 0, [](TValue total, const pair& p){ return total + p.second; }) }
{}
// Implements this algorithm
// http://stackoverflow.com/a/1761646/331024
const TKey get() const
{
// The real code uses c++11 <random> features,
// which I've removed for brevity.
auto weight_rand = static_cast< TValue >( std::rand() % sum_ );
for ( std::size_t i = 0; i < TSize; ++i )
{
if (weight_rand < values_[i].second)
{
return values_[i].first;
}
weight_rand -= values_[i].second;
}
assert(false);
}
private:
array values_;
const TValue sum_;
};
enum class direction
{
NORTH,
SOUTH,
EAST,
WEST
};
// For convenience create a type to map the above
// four-value enumeration to integer weights.
using w4i = weights< direction, int, 4 >;
// Map the directions with a weight.
static const w4i direction_weights = w4i::array{
{
w4i::pair{ direction::NORTH, 2 },
w4i::pair{ direction::EAST, 1 },
w4i::pair{ direction::SOUTH, 3 },
w4i::pair{ direction::WEST, 1 }
}
};
int main()
{
std::cout << (int)direction_weights.get() << std::endl;
return 0;
}
ICAgICNpbmNsdWRlIDxjYXNzZXJ0PgogICAgI2luY2x1ZGUgPGNzdGRsaWI+CiAgICAKICAgICNpbmNsdWRlIDxhcnJheT4KICAgICNpbmNsdWRlIDxpb3N0cmVhbT4KICAgICNpbmNsdWRlIDxudW1lcmljPgogICAgI2luY2x1ZGUgPHV0aWxpdHk+CgogICAgLy8gV3JhcHMgYSBzdGQ6OmFycmF5IG9mIFRLZXkvVFZhbHVlIHBhaXJzIGFuZCBwcm92aWRlcyBhIG1ldGhvZAogICAgLy8gdG8gcmFuZG9tbHkgc2VsZWN0IGEgVEtleSB3aXRoIFRWYWx1ZSBiaWFzLgogICAgdGVtcGxhdGU8IHR5cGVuYW1lIFRLZXksIHR5cGVuYW1lIFRWYWx1ZSwgc3RkOjpzaXplX3QgVFNpemUgPgogICAgY2xhc3Mgd2VpZ2h0cyBmaW5hbAogICAgewogICAgICAgIHB1YmxpYzoKICAgICAgICAgICAgdXNpbmcgcGFpciA9IGNvbnN0IHN0ZDo6cGFpcjwgY29uc3QgVEtleSwgY29uc3QgVFZhbHVlID47CiAgICAgICAgICAgIHVzaW5nIGFycmF5ID0gY29uc3Qgc3RkOjphcnJheTwgcGFpciwgVFNpemUgPjsKICAgIAogICAgICAgICAgICB3ZWlnaHRzKCBhcnJheSB2YWx1ZXMgKQogICAgICAgICAgICAgICAgOiB2YWx1ZXNfeyB2YWx1ZXMgfQogICAgICAgICAgICAgICAgLCBzdW1feyBzdGQ6OmFjY3VtdWxhdGUodmFsdWVzXy5iZWdpbigpLCB2YWx1ZXNfLmVuZCgpLCAwLCBbXShUVmFsdWUgdG90YWwsIGNvbnN0IHBhaXImIHApeyByZXR1cm4gdG90YWwgKyBwLnNlY29uZDsgfSkgfQogICAgICAgICAgICB7fQoKICAgICAgICAgICAgLy8gSW1wbGVtZW50cyB0aGlzIGFsZ29yaXRobQogICAgICAgICAgICAvLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNzYxNjQ2LzMzMTAyNAogICAgICAgICAgICBjb25zdCBUS2V5IGdldCgpIGNvbnN0CiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vIFRoZSByZWFsIGNvZGUgdXNlcyBjKysxMSA8cmFuZG9tPiBmZWF0dXJlcywKICAgICAgICAgICAgICAgIC8vIHdoaWNoIEkndmUgcmVtb3ZlZCBmb3IgYnJldml0eS4KICAgICAgICAgICAgICAgIGF1dG8gd2VpZ2h0X3JhbmQgPSBzdGF0aWNfY2FzdDwgVFZhbHVlID4oIHN0ZDo6cmFuZCgpICUgc3VtXyApOwoKICAgICAgICAgICAgICAgIGZvciAoIHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgVFNpemU7ICsraSApCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHdlaWdodF9yYW5kIDwgdmFsdWVzX1tpXS5zZWNvbmQpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWVzX1tpXS5maXJzdDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgd2VpZ2h0X3JhbmQgLT0gdmFsdWVzX1tpXS5zZWNvbmQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBhc3NlcnQoZmFsc2UpOwogICAgICAgICAgICB9CgogICAgICAgIHByaXZhdGU6CiAgICAgICAgICAgIGFycmF5IHZhbHVlc187CiAgICAgICAgICAgIGNvbnN0IFRWYWx1ZSBzdW1fOwogICAgfTsKCiAgICBlbnVtIGNsYXNzIGRpcmVjdGlvbgogICAgewogICAgICAgIE5PUlRILAogICAgICAgIFNPVVRILAogICAgICAgIEVBU1QsCiAgICAgICAgV0VTVAogICAgfTsKCiAgICAvLyBGb3IgY29udmVuaWVuY2UgY3JlYXRlIGEgdHlwZSB0byBtYXAgdGhlIGFib3ZlCiAgICAvLyBmb3VyLXZhbHVlIGVudW1lcmF0aW9uIHRvIGludGVnZXIgd2VpZ2h0cy4KICAgIHVzaW5nIHc0aSA9IHdlaWdodHM8IGRpcmVjdGlvbiwgaW50LCA0ID47CgogICAgLy8gTWFwIHRoZSBkaXJlY3Rpb25zIHdpdGggYSB3ZWlnaHQuCiAgICBzdGF0aWMgY29uc3QgdzRpIGRpcmVjdGlvbl93ZWlnaHRzID0gdzRpOjphcnJheXsKICAgICAgICB7CiAgICAgICAgICAgIHc0aTo6cGFpcnsgZGlyZWN0aW9uOjpOT1JUSCwgMiB9LAogICAgICAgICAgICB3NGk6OnBhaXJ7IGRpcmVjdGlvbjo6RUFTVCwgMSB9LAogICAgICAgICAgICB3NGk6OnBhaXJ7IGRpcmVjdGlvbjo6U09VVEgsIDMgfSwKICAgICAgICAgICAgdzRpOjpwYWlyeyBkaXJlY3Rpb246OldFU1QsIDEgfQogICAgICAgIH0KICAgIH07CgogICAgaW50IG1haW4oKQogICAgewogICAgICAgIHN0ZDo6Y291dCA8PCAoaW50KWRpcmVjdGlvbl93ZWlnaHRzLmdldCgpIDw8IHN0ZDo6ZW5kbDsgICAgCiAgICAKICAgICAgICByZXR1cm4gMDsKICAgIH0=
prog.cpp: In instantiation of ‘weights<TKey, TValue, TSize>::weights(array) [with TKey = direction; TValue = int; unsigned int TSize = 4u; weights<TKey, TValue, TSize>::array = const std::array<const std::pair<const direction, const int>, 4u>]’:
prog.cpp:67:5: required from here
prog.cpp:20:137: error: could not convert ‘values’ from ‘weights<direction, int, 4u>::array {aka const std::array<const std::pair<const direction, const int>, 4u>}’ to ‘const std::pair<const direction, const int>’
, sum_{ std::accumulate(values_.begin(), values_.end(), 0, [](TValue total, const pair& p){ return total + p.second; }) }
^