9

I'm trying to create and use make_unique for std::unique_ptr, in the same way std::make_shared exists for std::shared_ptr described here. Herb Sutter mentions the possible implementation of make_unique that looks like this:

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

It doesn't seem to work for me. I'm using the following sample program:

// testproject.cpp : Defines the entry point for the console application.
#include "stdafx.h"

#include <iostream>
#include <memory>
#include <utility>

struct A {
  A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
  A(int& n)  { std::cout << "lvalue overload, n=" << n << "\n"; }
};

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

int main() {
  std::unique_ptr<A> p1 = make_unique<A>(2); // rvalue
  int i = 1;
  std::unique_ptr<A> p2 = make_unique<A>(i); // lvalue
}

And the compiler (I'm using VS2010) gives me the following output:

1>d:\projects\testproject\testproject\testproject.cpp(15): error C2143: syntax error : missing ',' before '...'
1>d:\projects\testproject\testproject\testproject.cpp(16): error C2065: 'Args' : undeclared identifier
1>d:\projects\testproject\testproject\testproject.cpp(16): error C2988: unrecognizable template declaration/definition
1>d:\projects\testproject\testproject\testproject.cpp(16): error C2059: syntax error : '...'
1>d:\projects\testproject\testproject\testproject.cpp(22): error C2143: syntax error : missing ';' before '{'
1>d:\projects\testproject\testproject\testproject.cpp(22): error C2447: '{' : missing function header (old-style formal list?)

Also if you replace the make_unique implementation to the following

template<class T, class U>
std::unique_ptr<T> make_unique(U&& u) {
  return std::unique_ptr<T>(new T(std::forward<U>(u)));
}

(which is taken from this example), it compiles and works fine.

Can anyone tell me what's the problem? It seems to me that VS2010 is having some trouble with ... in template declaration, and I don't know what can I do about it.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Saage
  • 363
  • 1
  • 3
  • 12
  • 4
    Variadic Templates are only supported as of the CTP. – Stephan Dollberg Dec 14 '12 at 17:55
  • 2
    You should note that Herb Sutter's suggestion is not suitable for array types. Stephan T Lavavej posted an improved version in his recent episode of Core C++ that works for arrays, too, like `make_unique(1, 2, 3)`. – Kerrek SB Dec 14 '12 at 17:59
  • 2
    [here is a link to the `make_unique` that KerrekSB mentioned](http://stackoverflow.com/a/13512344/845092) – Mooing Duck Dec 14 '12 at 18:02
  • 1
    If you would like to use variadic templates in visual studio you need the latest updates. My own instructions: http://scrupulousabstractions.tumblr.com/post/36204698243/setupcpp11-msvs – Johan Lundberg Dec 14 '12 at 20:16
  • Your make_unique example doesn't compile for me. I get `error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'` – Tom Lint Oct 12 '17 at 19:48

2 Answers2

14

Variadic templates aren't available in the released version of Visual C++ 11. You can, however, simulate the argument expansion with either lots of copy/paste code for different number of parameters, or use the same compiler tricks used in Microsoft's own implementation of "pseudo-variadics". From this comment on Herb Sutter's blog: http://herbsutter.com/gotw/_102/#comment-6428

#include <memory> // brings in TEMPLATE macros.

#define _MAKE_UNIQUE(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)  \
\
template<class T COMMA LIST(_CLASS_TYPE)>    \
inline std::unique_ptr<T> make_unique(LIST(_TYPE_REFREF_ARG))    \
{    \
    return std::unique_ptr<T>(new T(LIST(_FORWARD_ARG)));    \
}

_VARIADIC_EXPAND_0X(_MAKE_UNIQUE, , , , )
#undef _MAKE_UNIQUE
Bret Kuhns
  • 4,034
  • 5
  • 31
  • 43
  • 3
    Note: the use of `_[A-Z].*` identifiers is reserved to the implementation (in your case, the VC++ compiler and the Dirkumware STL). – Matthieu M. Dec 14 '12 at 20:48
  • 1
    @MatthieuM. Thanks for pointing that out, I personally don't like to start identifiers with `_`. When I implemented `make_unique()` at work, I expanded the code to 10 parameters by hand (err, copy/paste) and dumped it in a utility namespace to avoid conflicting with a future `std` implementation. – Bret Kuhns Dec 15 '12 at 01:25
5

According to MSDN, variadic templates are not supported in Visual C++ 2010 or 2012.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644