C++ 11:使用容器参数定义函数(如基于范围)?

And*_*zos 13 c++ c++11

在C++ 11中经常需要定义一个以容器作为参数的函数.

例如,让我们定义一个函数addup(是的只是一个简单的版本std::accumulate):

template <class I>
int addup (I first, I last)
{
    int x = 0;
    while ( first != last )
        x += *first++;
    return x;
}
Run Code Online (Sandbox Code Playgroud)

这需要一个迭代器范围,这是灵活的标准库惯用法.

但是假设我有一个功能:

vector<T> f();
Run Code Online (Sandbox Code Playgroud)

我必须这样做:

auto v = f();
int x = addup(v.begin(), v.end());
Run Code Online (Sandbox Code Playgroud)

我宁愿这样做:

int x = addup(f());
Run Code Online (Sandbox Code Playgroud)

就像我可以这样做:

for (auto t : f())
    ...
Run Code Online (Sandbox Code Playgroud)

本着基于范围的精神,我想要这样的事情:

template<class C>
int addup(C&& container)
{
    addup(beginexpr(container), endexpr(container)); // ???
}
Run Code Online (Sandbox Code Playgroud)

在标准中它在6.5.4(释义)中说:

(A)if container是数组类型,beginexpr并且endexpr分别是containercontainer+ bound,bound数组绑定的位置.

(B)如果container是一个类型时,不合格的IDS beginend被查找类的范围container由类成员访问查找(3.4.5)那样的话,并且如果任一个(或两者)找到至少一个声明,beginexprendexpr是container.begin()和container.end()分别;

(C)否则,beginexpr并且endexpr分别是begin(container)end(container)依赖于参数的查找(3.4.2)查找开始和结束的地方.

是否可以定义一组重载或特殊化,addup以便它能处理这四种情况,而不是与其他重载冲突?首先是常规迭代器对函数,然后是A,B和C中的每一个.怎么样?

(如果这可能比为什么标准库不提供这样的重载?)

另外,如果函数在容器之外需要额外的参数怎么办?我们是否可以修改重载,使得添加到所有参数可选额外参数x(具有默认值的参数)不会使以下两个调用不明确:

addup(v.begin(), v.end());
addup(v, x);
Run Code Online (Sandbox Code Playgroud)

那我们可以静态断言(使用"SFINAE"或类似的)模板参数必须是迭代器,数组,容器类等 - 并且这些信息用于过载消歧吗?

Pub*_*bby 11

这就是我要做的:

template<class Range>
int addup(Range&& range)
{
    using std::begin;
    using std::end;
    addup(begin(range), end(range));  // begin(), NOT std::begin()  (ADL)
}
Run Code Online (Sandbox Code Playgroud)

它将处理所有重要的情况并正确地进行ADL.我不确定它是否等同于基于范围的for,但在我看来它是最好的解决方案.

以下两个调用含糊不清:

我没有编译,但除非x需要隐式转换,否则我看不到任何歧义.您还可以使用boost::make_iterator_range并避免迭代器参数重载.


我认为这也有效:

template<class Range>
int addup(Range&& range)
{
    int x = 0;
    for(auto&& v : range)
        x += v;
    return x; 
}

template <class I>
int addup (I first, I last)
{
    return addup(boost::make_iterator_range(first, last));
}
Run Code Online (Sandbox Code Playgroud)