Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does add_lvalue_reference do?

Tags:

c++

c++11

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!

like image 424
shuttle87 Avatar asked Feb 24 '11 17:02

shuttle87


1 Answers

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 type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR.

[ 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; If T names an object or function type then the member typedef type shall name T&; otherwise, if T names a type “rvalue reference to T1” then the member typedef type shall name T1&; otherwise, type shall name T.

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 cv1 S”, an attempt to create the type “reference to cv2 T” creates the type “reference to cv12 S”, 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 ]

like image 124
Ben Voigt Avatar answered Oct 14 '22 07:10

Ben Voigt