Question

I've found a trick to use optional reference in standard C++11. Do you think that this technique is reliable and the behaviour is well defined according to the the C++ standard ?

// Optional reference using C++11 
// V. Reverdy - 2013
#include <iostream>
#include <type_traits>

template <class T = int, class = typename std::enable_if<std::is_same<typename std::decay<T>::type, int>::value>::type>
void f(T&& n = T())
{
    std::cout<<"--------"<<std::endl;
    std::cout<<"is const = "<<std::is_const<T>::value<<std::endl;
    std::cout<<"is reference = "<<std::is_reference<T>::value<<std::endl;
    std::cout<<"is lvalue reference = "<<std::is_lvalue_reference<T>::value<<std::endl;
    std::cout<<"is rvalue reference = "<<std::is_rvalue_reference<T>::value<<std::endl;
    std::cout<<"--------"<<std::endl;
    n *= 2;
} 

int main(int argc, char* argv[])
{
    int n = 42;
    std::cout<<"n = "<<n<<std::endl;
    f();
    std::cout<<"n = "<<n<<std::endl;
    f(n);
    std::cout<<"n = "<<n<<std::endl;
    return 0;
}

The result is :

n = 42
--------
is const = 0
is reference = 0
is lvalue reference = 0
is rvalue reference = 0
--------
n = 42
--------
is const = 0
is reference = 1
is lvalue reference = 1
is rvalue reference = 0
--------
n = 84

It seems to work on all compilers available on liveworkspace : LWS

Was it helpful?

Solution

Wat.

Firstly, what you have "achieved" could be far simpler achieved by, say, overloading. And secondly, it is not the same as an optional reference at all. The optional reference is a value, which may or may not contain a reference at run-time. The behaviour is well-defined but it's neither desirable nor an optional reference. Binding references to temporaries as default arguments is nice in some situations but it's a billion miles from an optional reference.

OTHER TIPS

It is well-defined, yes, because "universal references" (mind the fact that this is a non-standard term) can resolve into rvalue references and therefore bind to temporaries, but you're not creating an "optional reference".

References must always be initialized and must always be bound to an object, they cannot be "bound or not bound" (which is my intuitive understanding of what you mean by "optional reference").

Here, you are simply binding that reference to a temporary. What you did is equivalent to the following:

template<typename T> void f(T&& t) { ... }
void f() { f(int()); }

If you meant to say the you are now able to create a function which accepts a reference and may be invoked without providing any argument - which is IMO a more correct way to put it - then this is true, but I wouldn't consider it a breaking discovery.

Even in C++03 you could do something similar, although for references to const only:

template<typename T>
void f(T const& = T()) { ... }

Since C++11 introduced non-const references which can bind to temporaries (rvalue references), a natural generalization follows, which is what your technique exploits.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top