# C++ lazy constructor

I'm implementing a lazy constructor in C++. The goal is that for a type T, lazy<T>(args...) returns a callable object which, when called, returns T(args...).

This is what I have done so far:

#include <functional>
#include <utility>

/**
* Returns an object of type T constructed from args.
*/
template<typename T, typename... Args>
T make(Args&&... args)
{
return T(std::forward<Args>(args)...);
}

/**
* Wrap a value of type T and perfect-forward it when accessed.
*/
template<typename T>
class Forward {
public:
Forward(T &&value) noexcept : value_(std::forward<T>(value))
{}

operator T()
{
return std::forward<T>(value_);
}

private:
T value_;
};

/**
* Returns a callable object which, when called, returns
* an object of type T constructed from args.
*/
template<typename T, typename... Args>
auto lazy(Args&&... args) -> decltype(
std::bind(
make<T, Args...>,
Forward<Args>(std::forward<Args>(args))...))
{
return std::bind(
make<T, Args...>,
Forward<Args>(std::forward<Args>(args))...);
}


(Contrived) Examples:

// rvalue arguments
auto makePtr = lazy<std::unique_ptr<int>>(new int(123));
auto ptr = makePtr();

// lvalue arguments
int *rawPtr = new int(456);
auto makePtr2 = lazy<std::unique_ptr<int>>(rawPtr);
auto ptr2 = makePtr2();


Can this code be improved (particularly in terms of efficiency)?

UPDATE: The Forward class is used only as arguments to std::bind. Rationale:

Suppose we have a type Foo with constructor Foo(const std::unique_ptr<int> &). We can construct it by calling make<Foo, const std::unique_ptr<int> &>(someUniquePtr), for example.

However, std::bind(make<Foo, const std::unique_ptr<int> &>, someUniquePtr)() won't work (I think), because the reference-ness of the second argument to std::bind will be dropped. Wrapping it inside a std::cref works, but for packed arguments it seems the Forward class is the only solution I can come up with that works for all types.

It's possible that I misinterpreted the cause of this but here is an example of what I mean: https://godbolt.org/g/8w2Msa.

• what's the point of the std::forward on the operator T() -- doesn't that make it possible that _value would get moved out and no longer be accessible via further calls to operator T()? or if T can never be an rvalue reference type, then it seems the forward is pointless. or maybe I don't quite understand what forward does -- or maybe not exactly what operator t does – xaxxon May 3 '16 at 6:32
• @xaxxon You are correct that "value_ would get moved out and no longer be accessible via further calls to operator T()", but that's actually the point. Please see my update. – Zizheng Tai May 3 '16 at 6:36
• What behavior of std::bind are you trying to avoid by using your Forward class? – xaxxon May 3 '16 at 6:40
• @xaxxon Updated. This is a convoluted solution, maybe (and I hope) there is a better way! – Zizheng Tai May 3 '16 at 6:42
• @xaxxon godbolt.org/g/VhbOhe This is when it stops working for me...maybe I miss interpreted the cause of the error? – Zizheng Tai May 3 '16 at 6:57

I think you can really simplify your code with the use of lambdas.

template<typename T, typename... Args>
auto make_lazy(Args&&... args)
{
return [=]{return T(std::move(args)...);};
}


Usage example:

#include <iostream>
class T
{
int v;
public:
T(int v): v(v) {std::cout << "Building T\n";}
friend std::ostream& operator<<(std::ostream& s, T const& out) {return s << "T: " << out.v << "\n";}
};
class S
{
int v;
public:
S(int v): v(v) {std::cout << "Building S\n";}
friend std::ostream& operator<<(std::ostream& s, S const& out) {return s << "S: " << out.v << "\n";}
};

template<typename T, typename... Args>
auto make_lazy(Args&&... args)
{
return [=]{return T(std::move(args)...);};
}

int main()
{
auto lazyT = make_lazy<T>(1);
auto lazyS = make_lazy<S>(2);

std::cout << "Building\n";
std::cout << lazyT() << "\n";
std::cout << lazyS() << "\n";
}

• Does the make_lazy actually do what we expect it to do? The capture takes everything by value. (Maybe c++14 can prevent copies) + The members of the lambda are constants, so you need to make your lambda mutable in order to prevent a second copy. – JVApen May 8 '16 at 21:23