c++ - Why does creating a temporary instance not work in this case? -
i've been learning c++11 through bjarne stroustrup's "a tour of c++".
i have following snippet of code
#include <random> #include <functional> int main(int argc, char *argv[]) { using namespace std; std::default_random_engine generator; std::uniform_int_distribution<int> distribution {1,6}; distribution(generator); //case 1 works auto die = bind(uniform_int_distribution<>{1,6},default_random_engine{}); //case 2 works distribution(std::default_random_engine{}); //case 3 compiler error }
case 3 own creation while case 2 comes book , case 1 adapted elsewhere. why case 3 produce compiler error below? far understand, difference between case 1 , case 3 i'm using temporary instance of std::default_random_engine , temporary instance seems work in case 2 missing?
error output:
random.cpp: in function ‘int main(int, char**)’: random.cpp:13:46: error: no match call ‘(std::uniform_int_distribution<int>) (std::default_random_engine)’ distribution(std::default_random_engine{}); //case 3 compiler error ^ in file included /usr/include/c++/6.3.1/bits/random.h:35:0, /usr/include/c++/6.3.1/random:49, random.cpp:1: /usr/include/c++/6.3.1/bits/uniform_int_dist.h:164:2: note: candidate: std::uniform_int_distribution<_inttype>::result_type std::uniform_int_distribution<_inttype>::operator()(_uniformrandomnumbergenerator&) [with _uniformrandomnumbergenerator = std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>; _inttype = int; std::uniform_int_distribution<_inttype>::result_type = int] <near match> operator()(_uniformrandomnumbergenerator& __urng) ^~~~~~~~ /usr/include/c++/6.3.1/bits/uniform_int_dist.h:164:2: note: conversion of argument 1 ill-formed: random.cpp:13:23: error: invalid initialization of non-const reference of type ‘std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>&’ rvalue of type ‘std::default_random_engine {aka std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>}’ distribution(std::default_random_engine{}); //case 3 compiler error ^~~~~~~~~~~~~~~~~~~~~~~ in file included /usr/include/c++/6.3.1/bits/random.h:35:0, /usr/include/c++/6.3.1/random:49, random.cpp:1: /usr/include/c++/6.3.1/bits/uniform_int_dist.h:169:2: note: candidate: template<class _uniformrandomnumbergenerator> std::uniform_int_distribution<_inttype>::result_type std::uniform_int_distribution<_inttype>::operator()(_uniformrandomnumbergenerator&, const std::uniform_int_distribution<_inttype>::param_type&) [with _uniformrandomnumbergenerator = _uniformrandomnumbergenerator; _inttype = int] operator()(_uniformrandomnumbergenerator& __urng, ^~~~~~~~ /usr/include/c++/6.3.1/bits/uniform_int_dist.h:169:2: note: template argument deduction/substitution failed: random.cpp:13:46: note: candidate expects 2 arguments, 1 provided distribution(std::default_random_engine{}); //case 3 compiler error ^
distribution(generator);
distribution
modifies state of generator
, , extracts value. on next call, returns different value, using same generator
auto die = bind(uniform_int_distribution<>{1,6},default_random_engine{});
here, copy both uniform_int_distribution<>{1,6}
, default_random_engine{}
bind function object. on ()
passes default_random_engine{}
uniform_int_distribution<>{1,6}
via operator()
. uniform_int_distribution<>{1,6}
modifies state of default_random_engine{}
, on next call, returns different value, uses (now modified) generator.
distribution(std::default_random_engine{});
here attempt bind random_engine&
temporary object. distribution
wants modify random engine's state, why taken reference.
by passing in temporary, such change discarded instantly. easy accidentally , screw up, c++ default not let bind temporary object non-const lvalue reference.
the designers of c++ std wanted error, took distribution non-const lvalue reference. trying tell "this bad plan".
you can work around it:
template<class t> t& as_lvalue(t&& t){ return t; }
now
distribution(as_lvalue(std::default_random_engine{}));
fools compiler thinking default_random_engine
passed in not temporary. still goes away @ end of line , modification state of generator, done distribution, discarded.
this not want when generating pseudo-random objects, c++11's random engine about.
in short, not permitted bind temporaries non-constant lvalue references. when so, error. when have parameter intended both read , written to, , written value important, taken non-constant lvalue reference, in order prevent casually passing in temporary , having data written lost.
generators stateful. want keep 1 around , repeatedly apply distribution it.
Comments
Post a Comment