37

My compiler doesn't support make_unique. How to write one?

template< class T, class... Args > unique_ptr<T> make_unique( Args&&... args );
sasha.sochka
  • 14,395
  • 10
  • 44
  • 68
user1899020
  • 13,167
  • 21
  • 79
  • 154
  • possible duplicate of [Is there a way to write make_unique() in VS2012?](http://stackoverflow.com/q/12547983/341970) – Ali Jul 27 '13 at 22:53

2 Answers2

51

Copied from make_unique and perfect forwarding (the same is given in Herb Sutter's blog)

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

If you need it in VC2012, see Is there a way to write make_unique() in VS2012?


Nevertheless, if the solution in sasha.sochka's answer compiles with your compiler, I would go with that one. That is more elaborate and works with arrays as well.

Community
  • 1
  • 1
Ali
  • 56,466
  • 29
  • 168
  • 265
  • 1
    Why do the dots go outside the args parentheses? That's so counterintuitive to me! – Apollys supports Monica Mar 29 '19 at 02:51
  • @Apollys If I understand your question correctly: That would expand the arguments to `std::forward`, and not to `T`. (Maybe I misunderstand your question.) – Ali Mar 29 '19 at 10:28
  • Likely that is what I was asking, I don't know much about the `...` syntax, only what I have seen in examples. What seems weird to me is that in the line `std::forward(args)...` it seems that `args` now somehow means each parameter individually while at the top it meant all of the parameters as a unit. – Apollys supports Monica Mar 29 '19 at 23:30
  • @Apollys Yeah, C++ is a weird language, full of such quirks. :( – Ali Mar 29 '19 at 23:38
  • 1
    This won't work when calling `make_unique` to create an array type like `unsigned char[]` and yields the error message `Allocation of incomplete type`. – BullyWiiPlaza Sep 24 '19 at 15:45
  • @BullyWiiPlaza Read the answer again: I made it very explicit that this does not work with arrays (hint: the last two sentences). – Ali Sep 24 '19 at 17:45
50

Version by Stephan T. Lavavej (also known by STL) who originally proposed adding this function to C++14

#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>

namespace std {
    template<class T> struct _Unique_if {
        typedef unique_ptr<T> _Single_object;
    };

    template<class T> struct _Unique_if<T[]> {
        typedef unique_ptr<T[]> _Unknown_bound;
    };

    template<class T, size_t N> struct _Unique_if<T[N]> {
        typedef void _Known_bound;
    };

    template<class T, class... Args>
        typename _Unique_if<T>::_Single_object
        make_unique(Args&&... args) {
            return unique_ptr<T>(new T(std::forward<Args>(args)...));
        }

    template<class T>
        typename _Unique_if<T>::_Unknown_bound
        make_unique(size_t n) {
            typedef typename remove_extent<T>::type U;
            return unique_ptr<T>(new U[n]());
        }

    template<class T, class... Args>
        typename _Unique_if<T>::_Known_bound
        make_unique(Args&&...) = delete;
}

EDIT: updated code to the N3656 standard revision

sasha.sochka
  • 14,395
  • 10
  • 44
  • 68
  • How does the `_Known_bound` struct match when no use of `_Unique_if` specifies a second template argument and there is no default? – Ben Jackson Jul 27 '13 at 21:44
  • 2
    @BenJackson The intent is for there to never be a match for the `_Known_bound` version when `make_unique` is used correctly. If someone tries to use it as `make_unique()` it'll match the `_Known_bound` version and result in an error. – Praetorian Jul 27 '13 at 22:56
  • 2
    What's a good way to include this definition in C++ code that may eventually be compiled in an environment where make_unique is available in stdc++? – Andreas Yankopolus Dec 16 '14 at 00:42
  • 3
    @AndreasYankopolus I'd suggest #if __cplusplus == 201103L ... #endif (see __cplusplus entry near the end of https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html ) – Keiji Apr 17 '15 at 06:58
  • 4
    Note that we are not allowed to put things into std:: like this. I'd rather use my own utilities namespace if I had to add `make_unique`. – Johan Lundberg Mar 25 '16 at 21:32
  • 1
    you might check for __cplusplus version to avoid problems. – sasha.sochka Mar 25 '16 at 21:34