阅读this question的答案,我惊讶地发现std::min(std::initializer_list<T>)
按价值得出了它的论点。
如果以其名称隐含的方式使用std::initializer_list
,即作为某个对象的初始化程序,我理解我们不关心复制其元素,因为它们将被复制以初始化对象。但是,在这种情况下,我们很可能不需要任何副本,因此如果只有可能的话,将参数作为std::initializer_list<const T&>
似乎更合理。
这种情况的最佳做法是什么?如果您不关心不制作不必要的副本,或者是否有其他一些技巧可以避免复制,您是否应该调用initializer_list
std::min
版本的版本?
答案 0 :(得分:6)
没有std::initializer_list<const T&>
之类的东西。初始化列表只能按值保存对象。
见[dcl.init.list] / 5:
类型为
std::initializer_list<E>
的对象是从初始化列表构造的,就好像实现分配了一个类型为const E
的N个元素的临时数组,其中N是初始化列表中元素的数量。 / p>
没有引用数组,因此也不能有initializer_list
个引用。
我在这种情况下的建议是为std::min
编写一个替代版本,它取代转发引用的可变参数模板。这有效(虽然我确信它可以改进):
template<typename T, typename... Args>
T vmin( T arg1, Args&&... args )
{
T *p[] = { &arg1, &args... };
return **std::min_element( begin(p), end(p),
[](T *a, T *b) { return *a < *b; } );
}
See it working - 使用min
或mmin
,制作了两份额外的副本(a
和b
)。
答案 1 :(得分:3)
总结评论:
如cppreference.com所述,std::initializer_list
应该是轻量级代理。
因此,初始化程序列表的副本应该非常快,因为不会复制基础元素:
C ++11§18.9/ 2
initializer_list<E>
类型的对象提供对const E.
类型对象数组的访问 [注意: 一对指针或指针加上长度将是initializer_list
的明显表示。initializer_list
用于实现8.5.4中指定的初始化列表。复制初始化列表不会复制基础元素。 - 结束记录]
使用引用虽然可以归结为使用指针,因此也是一个额外的间接。
因此,std::min
的实际问题不在于它需要initializer_list
的值,而是在运行时计算initializer_list
的参数必须被复制。 [1]
[1]中的基准[1]被打破了later是不幸的。
auto min_var = std::min({1, 2, 3, 4, 5}); // fast
auto vec = std::vector<int>{1, 2, 3, 4, 5};
min_var = std::min({vec[0], vec[1], vec[2], vec[3], vec[4]}); // slow
[1]:N2722 p。 2