I have this class that makes a path for a montecarlo simulator where it takes creates paths of integers from an array of available ints. So for example we could have a path of length 3 drawn from the array containing {0,1,2,3,4} and this would for example generate 3,1,2 and 1,4,0.
//This path generator just generates a list of ints for each path
template< typename randgen >
class MCPathGen {
public:
typedef vector< int > mcpath_t;
typedef randgen randgen_t;
typedef typename add_lvalue_reference<randgen>::type randgen_ref_t;
MCPathGend(randgen_ref_t r) : m_rgen(r) {}
//generate a single path by shuffling a copy of blank_d
mcpath_t operator()() {
Chooser< randgen_t > choose(m_rgen);
mcpath_t path_temp(blank_d.begin(), blank_d.end());
random_shuffle(path_temp.begin(), path_temp.end(), choose);
return path_temp;
};
private:
randgen_ref_t m_rgen;
};
Now I'm not quite sure what my colleague has done by using typedef typename add_lvalue_reference<randgen>::type randgen_ref_t;
What does add_lvalue_reference do? Is this necessary for making the code work?
I have not seen this before, so any insight is appreciated!
Copying pseudo-random number generators means you'd get the same stream of "random" numbers from each, which is not desirable, so you need a reference there.
However, you could just say randgen&
.
According to [dcl.ref]
in draft 3225, just randgen&
will create an lvalue reference no matter what's passed in (type, lvalue-reference-type, or rvalue-reference-type), so I'd just use that.
Quote from the standard that controls this behavior:
If a typedef (7.1.3), a type template-parameter (14.3.1), or a decltype-specifier (7.1.6.2) denotes a type
TR
that is a reference to a typeT
, an attempt to create the type “lvalue reference to cvTR
” creates the type “lvalue reference toT
”, while an attempt to create the type “rvalue reference to cvTR
” creates the typeTR
.[ Example:
int i;
typedef int& LRI;
typedef int&& RRI;
LRI& r1 = i; // r1 has the type int&
const LRI& r2 = i; // r2 has the type int&
const LRI&& r3 = i; // r3 has the type int&
RRI& r4 = i; // r4 has the type int&
RRI&& r5 = i; // r5 has the type int&&
decltype(r2)& r6 = i; // r6 has the type int&
decltype(r2)&& r7 = i; // r7 has the type int&
— end example ]
From section [meta.trans.ref]
:
template <class T> struct add_lvalue_reference;
IfT
names an object or function type then the member typedeftype
shall nameT&
; otherwise, ifT
names a type “rvalue reference toT1
” then the member typedeftype
shall nameT1&
; otherwise, type shall nameT
.
They are exactly the same thing.
In C++03, they're the same thing too. From [type.arg.type]
:
If a template-argument for a template-parameter
T
names a type “reference to cv1S
”, an attempt to create the type “reference to cv2T
” creates the type “reference to cv12S
”, where cv12 is the union of the cv-qualifiers cv1 and cv2. Redundant cv-qualifiers are ignored.[ Example:
template < class T > class X {
void f( const T &);
/ ∗ . . . ∗ /
};
X< int & > x; / / X<int&>::f has the parameter type const int&
— end example ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With