make_unique 带大括号初始化
make_unique with brace initialization
https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique 写道 std::make_unique
可以实现为
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
这不适用于没有构造函数的普通结构。这些可以用大括号初始化,但没有非默认构造函数。示例:
#include <memory>
struct point { int x, z; };
int main() { std::make_unique<point>(1, 2); }
Compiling this 会让编译器抱怨缺少 2 参数构造函数,这是正确的。
我想知道,是否有任何技术原因不根据大括号初始化来定义函数?如
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
上述情况的works well enough。是否还有任何其他合法用例会破坏?
看到一般趋势似乎更喜欢用大括号进行初始化,我假设在该模板中制作大括号是规范的选择,但标准不这样做的事实可能表明我遗漏了一些东西.
有些 类 对 2 种初始化样式有不同的行为。例如
std::vector<int> v1(1, 2); // 1 element with value 2
std::vector<int> v2{1, 2}; // 2 elements with value 1 & 2
可能没有足够的理由选择一个而不是另一个;我认为标准只是选择一个并明确说明决定。
作为解决方法,您可能需要实施自己的 make_unique
版本。正如您所展示的,这不是一项艰苦的工作。
在 C++20 中,这将编译:
std::make_unique<point>(1, 2);
由于新规则 allowing initializing aggregates from a parenthesized list of values。
在 C++17 中,你可以这样做:
std::unique_ptr<point>(new point{1, 2});
不过,这不适用于 make_shared
。所以你也可以只创建一个工厂(作为练习向左转发):
template <typename... Args>
struct braced_init {
braced_init(Args... args) : args(args...) { }
std::tuple<Args...> args;
template <typename T>
operator T() const {
return std::apply([](Args... args){
return T{args...};
}, args);
}
};
std::make_unique<point>(braced_init(1, 2));
在 C++14 中,您必须实现 apply
并为 braced_init
编写一个工厂函数,因为还没有 CTAD - 但这些都是可行的。
Seeing how the general trend appears to prefer braces for initialization
需要引用。这是一个充满争议的话题——但我绝对不同意这种说法。
除了其他答案,在他的 presentation on C++17 中,Alisdair Meredith 给出了 make_unique
的以下实现:
template<typename T, typename... Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T> {
if constexpr (std::is_constructible<T, Args...>::value)
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
else
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
它使用 C+17 if constexpr
,但没有它也很容易重写。
有了这个版本,你可以做到这两点
auto v = make_unique<std::vector<int>>(10, 20); // *v is a vector of 10 elements
和
auto p = make_unique<point>(10, 20); // *p is a point (10, 20)
https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique 写道 std::make_unique
可以实现为
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
这不适用于没有构造函数的普通结构。这些可以用大括号初始化,但没有非默认构造函数。示例:
#include <memory>
struct point { int x, z; };
int main() { std::make_unique<point>(1, 2); }
Compiling this 会让编译器抱怨缺少 2 参数构造函数,这是正确的。
我想知道,是否有任何技术原因不根据大括号初始化来定义函数?如
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
上述情况的works well enough。是否还有任何其他合法用例会破坏?
看到一般趋势似乎更喜欢用大括号进行初始化,我假设在该模板中制作大括号是规范的选择,但标准不这样做的事实可能表明我遗漏了一些东西.
有些 类 对 2 种初始化样式有不同的行为。例如
std::vector<int> v1(1, 2); // 1 element with value 2
std::vector<int> v2{1, 2}; // 2 elements with value 1 & 2
可能没有足够的理由选择一个而不是另一个;我认为标准只是选择一个并明确说明决定。
作为解决方法,您可能需要实施自己的 make_unique
版本。正如您所展示的,这不是一项艰苦的工作。
在 C++20 中,这将编译:
std::make_unique<point>(1, 2);
由于新规则 allowing initializing aggregates from a parenthesized list of values。
在 C++17 中,你可以这样做:
std::unique_ptr<point>(new point{1, 2});
不过,这不适用于 make_shared
。所以你也可以只创建一个工厂(作为练习向左转发):
template <typename... Args>
struct braced_init {
braced_init(Args... args) : args(args...) { }
std::tuple<Args...> args;
template <typename T>
operator T() const {
return std::apply([](Args... args){
return T{args...};
}, args);
}
};
std::make_unique<point>(braced_init(1, 2));
在 C++14 中,您必须实现 apply
并为 braced_init
编写一个工厂函数,因为还没有 CTAD - 但这些都是可行的。
Seeing how the general trend appears to prefer braces for initialization
需要引用。这是一个充满争议的话题——但我绝对不同意这种说法。
除了其他答案,在他的 presentation on C++17 中,Alisdair Meredith 给出了 make_unique
的以下实现:
template<typename T, typename... Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T> {
if constexpr (std::is_constructible<T, Args...>::value)
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
else
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
它使用 C+17 if constexpr
,但没有它也很容易重写。
有了这个版本,你可以做到这两点
auto v = make_unique<std::vector<int>>(10, 20); // *v is a vector of 10 elements
和
auto p = make_unique<point>(10, 20); // *p is a point (10, 20)