I have a class whose constructor takes an initializer_list:
Foo::Foo(std::initializer_list<Bar*> bars)
If I attempt to create an object with a brace-enclosed initializer list directly, the initializer_list is correctly deduced:
Foo f ({ &b }); // std::initializer_list<Bar*> correctly deduced
However, when trying to do the same indirectly (with a variadic function template - in this case make_unique), the compiler is unable to deduce the initializer_list:
std::make_unique<Foo>({ &b }); // std::initializer_list<Bar*> not deduced
Error output:
error: no matching function for call to
‘make_unique(<brace-enclosed initializer list>)’
Questions:
{ &b } as a initializer_list<Boo*>?std::make_unique<Foo>({ &b }) which I desire?Full example below:
#include <initializer_list>
#include <memory>
struct Bar
{};
struct Foo
{
Foo(std::initializer_list<Bar*> bars)
{ }
};
int main()
{
Bar b;
// initializer_list able to be deduced from { &b }
Foo f ({ &b });
// initializer_list not able to be deduced from { &b }
std::unique_ptr<Foo> p = std::make_unique<Foo>({ &b });
(void)f;
return 0;
}
make_unique uses perfect forwarding.
Perfect forwarding is imperfect in the following ways:
It fails to forward initializer lists
It converts NULL or 0 to an integer, which can then not be passed to a value of pointer type.
It does not know what type its arguments will be, so you cannot do operations that require knowing their type. As an example:
struct Foo { int x; };
void some_funcion( Foo, Foo ) {};
template<class...Args>
decltype(auto) forwarding( Args&& ... args ) {
return some_function(std::forward<Args>(args)...);
}
Calling some_function( {1}, {2} ) is legal. It constructs the Foos with {1} and {2}.
Calling forwarding( {1}, {2} ) is not. It does not know at the time you call forwarding that the arguments will be Foos, so it cannot construct it, and it cannot pass the construction-initializer-list through the code (as construction-lists are not variables or expressions).
If you pass an overloaded function name, which overload cannot be worked out at the point of call. And a set of overloads is not a value, so you cannot perfect forward it through.
You cannot pass bitfields through.
It forces takes a reference to its arguments, even if the forwarded target does not. This "uses" some static const data in ways that can cause a program to be technically ill-formed.
A reference to an array of unknown size T(&)[] cannot be forwarded. You can call a function taking a T* with it, however.
About half of these were taken from this comp.std.c++ thread, which I looked for once I remembered there were other issues I couldn't recall off the top of my head.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With