在 C++11 中,我经常需要定义一个将容器作为参数的函数。
例如,让我们定义一个函数addup
(是的,只是一个简单的版本std::accumulate
):
template <class I>
int addup (I first, I last)
{
int x = 0;
while ( first != last )
x += *first++;
return x;
}
这需要一个迭代器范围,它是灵活的并且是标准库的习惯用法。
但是假设我有一个功能:
vector<T> f();
我必须这样做:
auto v = f();
int x = addup(v.begin(), v.end());
我宁愿这样做:
int x = addup(f());
就像我可以这样做:
for (auto t : f())
...
本着基于范围的精神,我想要这样的东西:
template<class C>
int addup(C&& container)
{
addup(beginexpr(container), endexpr(container)); // ???
}
在标准中,它在 6.5.4(释义)中说:
(A) if
container
是一个数组类型,beginexpr
并且endexpr
分别是 arecontainer
和container
+bound
,bound
数组绑定在哪里。(B) 如果
container
是类类型,则在类的范围内查找 unqualified-idsbegin
和就像通过类成员访问查找 (3.4.5) 一样,并且如果其中一个(或两者)找到至少一个声明,并且是container.begin() 和 container.end() 分别;end
container
beginexpr
endexpr
(C) 否则,
beginexpr
分别endexpr
是begin(container)
和end(container)
,其中 begin 和 end 使用参数相关查找 (3.4.2) 进行查找。
是否可以定义一组重载或特化addup
来处理这四种情况,而不与其他重载冲突?那首先是一个常规的迭代器对函数,然后是上面的 A、B 和 C 中的每一个。如何?
(如果这是可能的,那么为什么标准库不提供这样的重载?)
另外,如果函数在容器之外接受额外的参数怎么办?我们是否可以修改重载,使添加到所有重载的可选额外参数 x
(具有默认值的参数)不会使以下两个调用产生歧义:
addup(v.begin(), v.end());
addup(v, x);
那就是我们可以静态断言(使用“SFINAE”或类似的)模板参数必须是一个迭代器、一个数组、一个容器类等 - 并将这些信息用于重载消歧?