make_unique and perfect forwarding
Herb Sutter, chair of the C++ standardization committee, writes on his blog:
That C++11 doesn’t include
make_unique
is partly an oversight, and it will almost certainly be added in the future.
He also gives an implementation that is identical with the one given by the OP.
Edit: std::make_unique
now is part of C++14.
Perfect forwarding in std::make_uniqueSomeWrapperT not quite perfect
Why does this code compile:
auto compiles = std::make_unique<DataHolder<int>>(42);
auto alsoCompiles = std::make_unique<DataHolder<std::string>>("Hi");
DataHolder<int>
has a constructor taking int
, and 42
is passed as the constructor argument to construct DataHolder<int>
, which works fine (similarly as DataHolder<int>(42)
).
DataHolder<std::string>
has a constructor taking std::string
, and "Hi"
is passed as the constructor argument, it could convert to std::string
implicitly, which works fine (similarly as DataHolder<std::string>("Hi")
).
and this code does not:
auto doesnt = std::make_unique<DataHolder<Point>>({20, 21});
auto alsoDoesnt = std::make_unique<DataHolder<Widget>>("Hello");
std::make_unique<DataHolder<Point>>({20, 21})
doesn't work because braced-init-list like {20, 21}
doesn't have type, template argument deduction for std::make_unique
fails on it. This belongs to non deduced contexts.
- The parameter P, whose A is a braced-init-list, but P is not
std::initializer_list
, a reference to one (possibly cv-qualified), or a reference to an array:
DataHolder<Widget>
has a constructor taking Widget
, and "Hello"
is a const char[6]
which could decay to const char*
, then two user-defined conversions are required, one from const char*
to std::string
, one from std::string
to Widget
, but only one user-defined conversion is allowed in one implicit conversion sequence. (Similarly DataHolder<Widget>("Hello")
doesn't work either.)
If you pass Point
and std::string
directly, they would work fine.
auto doesnt = std::make_unique<DataHolder<Point>>(Point{20, 21});;
auto alsoDoesnt = std::make_unique<DataHolder<Widget>>(std::string{"Hello"});
As @YiFei suggested, you can make DataHolder
's constructor template, and forward all the arguments by std::forward
to the constructor of T
to initialize the data member directly, i.e. work in the similar way as std::make_unique
.
E.g.
template <typename... Args>
DataHolder(Args&&... value) : value {std::forward<Args>(value)...} {}
Note that std::make_unique<DataHolder<Point>>({20, 21});
still doesn't work for the reason above. But you can do std::make_unique<DataHolder<Point>>(20, 21);
instead, 20
and 21
are forwared to the constructor of Point
taking two int
s and then works fine. Similarly for std::make_unique<DataHolder<Widget>>("Hello")
, "Hello"
is forwarded to the constructor of Widget
taking std::string
, "Hello"
could convert to std::string
implicitly and then works fine.
Perfect forwarding of a braced initializer to a constructor?
In your first example WrappedSSimple({1,2})
is calling the move-constructor of WrappedSSimple
with the a temporary constructed via the user-defined constructor as argument.
You cannot replicate this behavior with a factory if the constructor is private, because the temporary object which needs access to the constructor is always created in the context of the caller.
You can also not generally forward untyped braces. The best you can do, if you are fine with restricting the types to be the same for each element of the brace, is to use a std::initializer_list
or a reference to an array as parameter to make
.
Indirect perfect forwarding via function pointer?
Background of the question is a mis-reading of Scott Meyer's article about forwarding references (called 'universal references' there).
The article gave the impression of such forwarding references existing as a separate type in parallel to ordinary l-value and r-value references. This is not the case, though, instead it is a hypothetical construct to explain special deduction rules that exist if template parameters serve as function parameter types.
As such a type does not exist in consequence it is not possible to declare a function pointer using that type, proving indirect perfect forwarding via function pointer impossible to realise.
c++ perfect forwarding with universal reference prevents type deduction?
In this case, you can add a default value to the U
template parameter like
template<typename U = T>
void set(U&& a) {
a_=std::forward<U>(a);
}
and now if it can deduce the type, like with {}
which has no type, then it will fall back t using T
as the type for U
.
std::move on const char* with perfect forwarding
What is
std::move
doing to aconst char [12]
and what are the potential side-effects?
The ordinary array-to-pointer implicit conversion, and none. Pointer types don't have move constructors or move assignment operators, so "moves" are copies (of the pointer the array decayed to).
Aside: I don't think your template does what you think it does. The pack T_Args...
isn't deduced in when calling Foo::foo
, so you don't have a universal reference, instead it's rvalue references.
Did you mean something like
template <typename... T_Args>
struct Foo
{
template <typename T_Func, typename... T_Args2>
void foo(T_Func func, T_Args2&&... args)
{
static_assert(std::is_constructible_v<T_Args, T_Args2> && ..., "Arguments must match parameters");
func(std::forward<T_Args2>(args)...);
}
};
Or possibly the even simpler
struct Foo
{
template <typename T_Func, typename... T_Args>
void foo(T_Func func, T_Args&&... args)
{
func(std::forward<T_Args>(args)...);
}
};
Perfect forwarding in the visitor pattern std::visit of C++
I can get rid of the perfect forwarding
Passing by a const reference would copy the lambdas instead of moving them.
It doesn't matter in your case, but it will matter if the lambdas capture things by value. It can hurt performance if the lambdas are expensive to copy, or cause a compilation error if the lambdas can't be copied (because they have non-copyable state, e.g. [x = std::make_unique<int>()](){}
).
I can get rid of the ... the deduction guide.
If you pass by const reference, yes. But if you pass by a forwarding reference, no.
The constructor having an independent set of template parameters is one problem. Buf if you used the same template parameters (and inherited from std::decay_t<B>...
instead), it still wouldn't work, because built-in deduction guides refuse to do perfect forwarding. The template argument deduction wouldn't work if you passed an lvalue.
A better question is why have a constructor at all. If you remove it, the type becomes an aggregate and everything continues to work as before.
It even lets you remove the deduction guide (except that Clang doesn't support that yet).
error perfect forwarding a lamda - discards qualifiers
To perfect forwarding use Functor&& func
- not const Functor&& func
Perfect forwarding with a specific type
You can assert it:
template<typename T>
void push(T&& value)
{
static_assert(is_same_v<remove_reference_t<T>, value_type>);
// ...
}
You could alternatively use is_convertible
instead of is_same
so it works more naturally.
Related Topics
Static Linking VS Dynamic Linking
How to Make a Http Request With C++
When Should You Use 'Friend' in C++
Difference Between an Int and a Long in C++
How to Implement Big Int in C++
Difference Between Char A[] = String; and Char *P = String;
Why Cast Unused Return Values to Void
Passing Arrays to Function in C++
Is "For(;;)" Faster Than "While (True)"? If Not, Why Do People Use It
Performance of Built-In Types: Char VS Short VS Int Vs. Float Vs. Double
Visual Studio Support For New C/C++ Standards
How to Check For C++11 Support
Linux API to List Running Processes
Difference Between Void Main and Int Main in C/C++
Is Sizeof(Bool) Defined in the C++ Language Standard
Sorting Zipped (Locked) Containers in C++ Using Boost or the Stl