I am giving an example below. The program compiles and runs fine, but I am wondering whether it is theoretically undefined behaviour according to the C++11 standard; can I return the result of binding a (temporary) local function object?
Example code (edited for short):
#include <iostream>
#include <functional>
struct MyFunctionObject
{
inline void operator() ( const std::string& name )
{ std::cout<< "Hello " << name << "!" << std::endl; }
};
std::function< void () > my_greeter( const std::string& name )
{
MyFunctionObject fun;
return std::bind( fun, name );
}
int main()
{
auto g = my_greeter("sheljohn");
g();
}
EDIT Original example:
#include <random>
#include <functional>
#include <algorithm>
#include <utility>
#include <iostream>
/******************** ********** ********************/
/******************** ********** ********************/
namespace foo {
/**
* Type of the generator returned by the method 'bind' below.
*/
template <class _dist>
using generator_type = std::function< typename _dist::result_type () >;
// ------------------------------------------------------------------------
/**
* Wrapper for C++11 random library.
*/
template <
class _engine = std::mt19937_64,
class _device = std::random_device
>
struct random
{
typedef _engine engine_type;
typedef _device device_type;
typedef random<_engine,_device> self;
template <class _dist>
static inline generator_type<_dist>
bind( _dist& distribution )
{ return std::bind( distribution, self::engine ); }
template <class _dist>
static inline generator_type<_dist>
bind( _dist&& distribution )
{ return std::bind( distribution, self::engine ); }
static engine_type engine;
static device_type device;
};
// Initialize static engine
template <class _engine,class _device>
_device random<_engine,_device>::device;
template <class _engine,class _device>
_engine random<_engine,_device>::engine = _engine( device() );
// ------------------------------------------------------------------------
/**
* Generic binder to standard random distributions.
*
* SO QUESTION: does this cause undefined behaviour?
*/
template <class _dist, class... Args>
constexpr generator_type<_dist> random_generator( Args&&... args )
{ return random<>::bind( _dist( std::forward<Args>(args)... ) ); }
}; // namespace: foo
/******************** ********** ********************/
/******************** ********** ********************/
int main()
{
auto ngen = foo::random_generator< std::normal_distribution<double> >( 0.0, 1.0 );
for(unsigned i=0; i<10; ++i)
std::cout<< ngen() << " " << std::endl;
}
The standard actually has a specific bit about calling bind()
with a random number generator, in §26.5:
[ Note: These entities are specified in such a way as to permit the binding of any uniform random number generator object e as the argument to any random number distribution object d, thus producing a zero-argument function object such as given by bind(d,e). —end note ]
So what you're doing is explicitly allowed for.
Also from [func.bind.bind]
, the description states that when you call bind(F&& f, BoundArgs&&... bound_args)
that (emphasis mine):
FD
is the typedecay_t<F>
,fd
is an lvalue of typeFD
constructed fromstd::forward<F>(f)
Ti
is the ith type in the template parameter packBoundArgs
TiD
is the typedecay_t<Ti>
ti
is the ith type in the function parameter packbound_args
tid
is an lvalue of typeTiD
constructed fromstd::forward<Ti>(ti)
- ..
Returns: A forwarding call wrapper
g
... The effect ofg(,u1, u2, ..., uM)
shall beINVOKE(fd, std::forward<V1>(v1), std::forward<V2>(V2), ... std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ..., VN)>)
The section is a little confusing to me, but basically the functor and the arguments you pass in is forwarded (copied/move) into local version, fd
and tid...
. bind
won't keep a reference to the functor (FD
is not a reference type!), and the same is true of all of the arguments (the TiD
types for the BoundArgs
are not reference types either). So in your new example, even if fun
and the string that name
is a reference to both go out of scope, the bind()
result is still a valid callable.
There is no UB here.