将单个参数传递给期望迭代器范围的函数

pir*_*iri 21 c++ iterator stl iterator-range

考虑接受一个或多个参数(例如文件名)的函数.为了使其具有通用性,将其编写为通用迭代器范围是有利的:

template<class Iter>
void function(Iter first, Iter last)
{
  // do something
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以通过以下方式调用它,与我们存储参数的方式无关:

WhateverContainer container;
function(std::begin(container), std::end(container));
Run Code Online (Sandbox Code Playgroud)

例如,STL在很大程度上依赖于这种范例.

现在,假设我们想要使用未存储在容器中的单个参数来调用该函数.我们当然可以写:

const int value = 5;
std::vector<int> vec(1, value);
function(std::begin(vec), std::end(vec));
Run Code Online (Sandbox Code Playgroud)

但这个解决方案对我来说似乎很笨拙和浪费.

问题:是否有更好的低开销方法来创建单个变量的迭代器范围兼容表示?

Bau*_*gen 33

您可以使用指针一次:

function(&value, &value + 1);
Run Code Online (Sandbox Code Playgroud)

在通用代码中,取决于您的偏执程度,std::addressof而不是一元运算符&更安全一些.

你当然可以将它包装在一个重载中以便于使用:

template <class T>
decltype(auto) function (T &&e) {
    auto p = std::addressof(e);
    return function(p, p + 1);
}
Run Code Online (Sandbox Code Playgroud)

  • 看我的回答[使用std :: addressof()函数模板而不是在C++中使用&(address of)运算符有什么好处吗?](// stackoverflow.com/a/32680218) (6认同)

chr*_*ris 13

您可以将它视为每个[expr.unary.op]/3的一个元素数组:

function(&value, &value + 1);
Run Code Online (Sandbox Code Playgroud)

出于指针运算([expr.add])和比较([expr.rel],[expr.eq])的目的,不是以这种方式获取地址的数组元素的对象被认为属于数组使用一种T型元素

  • @Lingxi,也许,但这不是一个非常常见的情况,需要检测单个值而不是容器.这通常很难.例如,假设您想要传递单个容器. (2认同)

眠りネ*_*ネロク 6

您也可以重载你的函数模板function单元素范围:

template<typename Iter>
void function(Iter first) {
    return function(first, std::next(first)); // calls your original function
}
Run Code Online (Sandbox Code Playgroud)

这样,您的原始函数function仍然与迭代器范围兼容.但请注意,使用具有空范围的此重载将导致未定义的行为.


对于单个元素,value您可以使用上面的重载:

function(&value); // calls overload
Run Code Online (Sandbox Code Playgroud)

由于运算符&可能过载,因此请考虑使用std::addressof而不是&本答案中已提到的那样.


对于由单个元素组成的范围,您也可以使用上面的重载,它只需要一个迭代器而不是迭代器对:

const int value = 5;
std::vector<int> vec(1, value); // single-element collection
function(std::begin(vec)); // <-- calls overload
Run Code Online (Sandbox Code Playgroud)