数组 vs std::initializer_list 作为函数参数
array vs std::initializer_list as function parameter
我可以通过两种方式编写一个以临时数组(例如{1, 2, 3}
)作为参数的函数:
// using array
template<typename T, int N>
auto foo1(const T(&t)[N]) -> void;
// using std::initializer_list
template<typename T>
auto foo2(std::initializer_list<T> t) -> void;
是否有任何指南可以告诉您哪个更好?
它们是完全不同的东西。还有2、3个其他选择比较合理
template<class T, std::size_t N>
void foo_a( std::array<T, N> const& );
template<class T>
void foo_b( gsl::span<const T> );
template<class T, std::size_t N >
void foo_c( T const(&)[N] );
template<class T>
void foo_d( std::initializer_list<T> );
template<class T, class A=std::allocator<T> >
void foo_e( std::vector<T, A> const& );
template<class...Ts>
void foo_f( std::tuple<Ts...> const& );
template<class...Ts>
void foo_g( Ts const& ... );
这里有 7 种不同的方法来获取一堆 T
s。
它们各有优缺点。
最接近严格更好的是 foo_a
,超过 foo_c
; foo_c
唯一的好处是它与 C 风格的数组更兼容。
foo_b
允许您消耗除 foo_f
之外的任何其他内容。太好了。
a、c 和 f 的编译时长度都在 foo
以内。这可能会有所不同,具体取决于您在做什么。理论上您可以编写一个 foo_b
类型的视图来处理固定长度,但没有人会打扰。
e 是唯一在调用点支持动态长度的。
f 支持不同类型,但使迭代变得不那么干净。
所有这些都可以稍微修改以允许移出(即使是初始化列表中的样板文件更多)。
d 给出了最简单的 {}
,但是 g 也一样干净(完全省略了 {}
)。
通常我使用我的自制 gsl::span
变体。它有一个 initializer_list
构造函数。而且我很少想推断 T
.
我可以通过两种方式编写一个以临时数组(例如{1, 2, 3}
)作为参数的函数:
// using array
template<typename T, int N>
auto foo1(const T(&t)[N]) -> void;
// using std::initializer_list
template<typename T>
auto foo2(std::initializer_list<T> t) -> void;
是否有任何指南可以告诉您哪个更好?
它们是完全不同的东西。还有2、3个其他选择比较合理
template<class T, std::size_t N>
void foo_a( std::array<T, N> const& );
template<class T>
void foo_b( gsl::span<const T> );
template<class T, std::size_t N >
void foo_c( T const(&)[N] );
template<class T>
void foo_d( std::initializer_list<T> );
template<class T, class A=std::allocator<T> >
void foo_e( std::vector<T, A> const& );
template<class...Ts>
void foo_f( std::tuple<Ts...> const& );
template<class...Ts>
void foo_g( Ts const& ... );
这里有 7 种不同的方法来获取一堆 T
s。
它们各有优缺点。
最接近严格更好的是 foo_a
,超过 foo_c
; foo_c
唯一的好处是它与 C 风格的数组更兼容。
foo_b
允许您消耗除 foo_f
之外的任何其他内容。太好了。
a、c 和 f 的编译时长度都在 foo
以内。这可能会有所不同,具体取决于您在做什么。理论上您可以编写一个 foo_b
类型的视图来处理固定长度,但没有人会打扰。
e 是唯一在调用点支持动态长度的。
f 支持不同类型,但使迭代变得不那么干净。
所有这些都可以稍微修改以允许移出(即使是初始化列表中的样板文件更多)。
d 给出了最简单的 {}
,但是 g 也一样干净(完全省略了 {}
)。
通常我使用我的自制 gsl::span
变体。它有一个 initializer_list
构造函数。而且我很少想推断 T
.