【发布时间】:2018-05-28 12:50:55
【问题描述】:
我有一个向量向量,我想检查它们是否都是空的。使用标准库,我尝试了:
#include <algorithm>
#include <vector>
int main()
{
std::vector<std::vector<int>> vv;
std::all_of(std::begin(vv), std::end(vv), std::empty);
}
这会导致clang 7.0:中出现以下错误
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/stl_algo.h :508:5: 注意:候选模板被忽略:无法推断模板参数 '_谓词'
我想这是一种标准行为,由于类型推导的规则。但无论如何,解决这个问题的最简单方法是什么?
编辑:我接受了 rubenvb 的回答,因为他给出了简单合理的解释,以及自然的解决方法。 all_of 接受一个谓词,它是一个函数、一个函数对象或一个 lambda 表达式。 std::empty 不是那些,而是一个函数模板。当显式实例化它时,我们得到一个应该可以工作的普通函数。令人惊讶的是,它仍然无法在我尝试过的大多数编译器上编译。
好吧,让我们看看:
在 GCC 6.3 上,它编译得很好 - https://godbolt.org/g/Pxta7C
但在来自主干的 GCC 上,它会导致内部编译器错误 - https://godbolt.org/g/H6DHt5
trunk 或 MSVC 2017 中的 Clang 均无法成功编译:
https://godbolt.org/g/819pbQ (Clang)
https://godbolt.org/g/ua5E8e (MSVC)
EDIT2:显然,Robert Andrzejuk 也是对的:编译器无法处理它的原因是一个模棱两可的重载决议。 std::empty 有 3 种不同的重载。其中两个同样是很好的候选者:一般的一个和 std::initializer 列表一个。我使用以下最小版本获得了类似的结果:
#include <vector>
template<class T>
void foo(const T& t);
template<class T>
void foo(const std::initializer_list<T>& il);
template<class F>
void bar(F f);
int main()
{
bar(foo<std::vector<int>>);
}
不过,有一个区别。这个例子根本没有在 GCC 中从主干编译(而不是导致 ICE)。
【问题讨论】:
-
但是错误是什么?你发布的是笔记
-
std::empty是一个模板。all_of的第三个参数不是模板,而是闭包或可调用对象。您必须实例化模板:std::empty<std::vector<int>>{}。有可能只是std::empty{}也可以工作,没有费心去检查。 -
谢谢。但是,它仍然是一个函数模板,而不是类模板。所以这两个都不起作用。
-
@Shmuel 你是对的,看我的回答。只需删除大括号初始化
{}。