问题
I have a std::vector<float> weights;
containing the list of weights. I don't know what will be in this list until some stage in running the program. I would like to do
std::discrete_distribution<> dist(weights.begin(),weights.end());
but VS2013 doesn't appear to have a constructor for std::discrete_distribution that accepts an iterator range. Is there any workaround?
回答1:
Compare cppreference.com and the Microsoft reference for std::discrete_distribution
:
These are the constructors provided by VS2013:
discrete_distribution();
explicit discrete_distribution(
const param_type& par0
);
discrete_distribution(
initializer_list<double> IList
);
template<class Fn>
discrete_distribution(
size_t count,
double low,
double high,
Fn func
);
There is one important constructor missing, probably because the Microsoft developers didn't have the time to implement it:
template< class InputIt >
discrete_distribution( InputIt first, InputIt last );
That means, unless the documentation is incomplete, you simply can't use an iterator-based constructor for this class. Switch to another compiler (like clang or g++), or wait until this feature is implemented.
Now for a workaround you can use right now:
std::size_t i(0);
assert( !weights.empty() ); // No weights would be very weird.
std::discrete_distribution<> dist(weights.size(),
0.0, // dummy!
0.0, // dummy!
[&weights,&i](double)
{
auto w = weights[i];
++i;
return w;
});
I hope that at least lambdas are supported ;-) The important thing is to capture i
by reference, such that it gets properly incremented. Demo: http://ideone.com/nIBUts
Why does this work? The constructor we are using here is:
template< class UnaryOperation >
discrete_distribution( std::size_t count, double xmin, double xmax,
UnaryOperation unary_op );
The documentation on cppreference tells us that the count
(in our case weights.size()
), as well as the xmin
and xmax
is used to create the weights using the UnaryOperation
.
We are ignoring xmin
and xmax
on purpose. As the UnaryOperation
we use the lambda
[&weights,&i](double)
{
auto w = weights[i];
++i;
return w;
}
or
[&weights,&i](double)
{
return weights[i++];
}
if you prefer.
Now, we are ignoring the input value for that operator and just return the i^th element of our vector. We capture both the vector and the index by reference to avoid copies.
回答2:
std::discrete_distribution<> dist(
weights.size(),
-0.5,
-0.5+weights.size(),
[&weights](size_t i)
{
return weights[i];
});
or in terms of iterators:
//replacement code for: std::discrete_distribution<> dist(first, last);
auto first = weights.cbegin();
auto last = weights.cend();
auto count = std::distance(first, last);
std::discrete_distribution<> dist(
count,
-0.5,
-0.5+count,
[&first](size_t i)
{
return *std::next(first,i);
});
This avoids having to capture a mutable i
variable. The parameter passed to the lambda can be used as the index.
来源:https://stackoverflow.com/questions/21959404/initialising-stddiscrete-distribution-in-vs2013