https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique writes that std::make_unique
can be implemented as
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
This does not work for plain structs with no constructors. Those can be brace-initialized but don't have a non-default constructor. Example:
#include <memory>
struct point { int x, z; };
int main() { std::make_unique<point>(1, 2); }
Compiling this will have the compiler complain about lack of a 2-argument constructor, and rightly so.
I wonder, is there any technical reason not to define the function in terms of brace initialization instead? As in
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
That works well enough for the scenario above. Are there any other legitimate use cases this would break?
Seeing how the general trend appears to prefer braces for initialization, I would assume making braces in that template would be the canonical choice, but the fact that the standard doesn't do it might be an indication of me missing something.
Some classes have different behavior with the 2 initialization styles. e.g.
std::vector<int> v1(1, 2); // 1 element with value 2
std::vector<int> v2{1, 2}; // 2 elements with value 1 & 2
There might not be enough reason to choose one prefer to another; I think the standard just choose one and state the decision explicitly.
As the workaround, you might want to implement your own make_unique
version. As you have showed, it's not a hard work.