That code looks like some Template Meta Programming (TMP). It is used extensively in the STL, and in boost.
There will be a struct add_lvalue_reference<T> somewhere , that has a member type. These structs are used to build other types.
The type traits header <type_traits> is worthwhile looking at, one can see how these are built up. Edit: That's where add_lvalue_reference<T> is defined.
the below function swaps numbers passed by value by adding in the lvalue_reference along the way to variables initialized with the numbers passed by value:
#include <iostream>
#include <type_traits>
template <typename T>
void swap(T a, T b)
{
using Tref = typename std::add_lvalue_reference<T>::type;
Tref aRef = a;
Tref bRef = b;
T temp = aRef;
aRef = bRef;
bRef = temp;
std::cout << "The numbers swapped are " << aRef << " " << bRef << "\n";
}
int main()
{
int a {5};
int b {6};
swap (a, b);
}
edit: why use it? because sometimes we may not have control over source of a function's argument which could be the return value of yet another function and so we might need to add in the lvalue_reference explicitly
similary rvalue_reference (both add and remove) in the case of move semantics
> template< typename T > void f( typename std::add_lvalue_reference<T>::type r ) ;
> How can such a template function be invoked?
Because in the parameter, T appears to the left of ::, it appears in a non-deduced context.
The type has to be explicitly specified. For example: int i = 7 ; f<int>(i) ;
> Why would anyone want to use such a construct as a function template parameter?
Such a construct (force a template parameter to be in a non-deduced context) is useful when we do not want a particular argument to participate in template argument deduction, but we want it to use the type that was deduced for some other argument. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include <iostream>
#include <type_traits>
#include <string>
template< typename T > void foo( T&, typename std::remove_reference<T>::type ) {}
template< typename T > void bar( T&, T ) {}
int main ()
{
std::string a = "abcd" ;
foo( a, "efgh" ) ; // fine: T is deduced as std::string
bar( a, "efgh" ) ; // ***error: deduction failed (ambiguous)
double d = 7 ;
foo( d, 22 ) ; // fine: T is deduced as int double
bar( d, 22 ) ; // ***error: deduction failed (ambiguous)
}