c++ - 模板类型推导失败(std::empty 作为谓词)
问题描述
我有一个向量向量,我想检查它们是否都是空的。使用标准库,我尝试了:
#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:注意:候选模板被忽略:无法推断模板参数'_Predicate'
由于类型推导的规则,我想这是一种标准行为。但无论如何,解决这个问题的最简单方法是什么?
编辑:我接受了 rubenvb 的回答,因为他给出了简单合理的解释,以及自然的解决方法。all_of 接受一个谓词,它是一个函数、一个函数对象或一个 lambda 表达式。std::empty 不是那些,而是一个函数模板。当显式实例化它时,我们得到一个应该可以工作的普通函数。令人惊讶的是,它仍然无法在我尝试过的大多数编译器上编译。
好吧,走着瞧:
在 GCC 6.3 上,它编译得很好 - https://godbolt.org/g/Pxta7C
但在主干的 GCC 上,它会导致内部编译器错误 - https://godbolt.org/g/H6DHt5
来自主干或 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::all_of
。更好的解释:std::function 无法区分重载函数
所以要做到这一点,static_cast
需要正确的函数类型bool ( * )( const std::vector< int >& )
:
std::all_of( vv.begin(), vv.end(),
static_cast< bool ( * )( const std::vector< int >& ) >( std::empty ) );
使用有关所需的知识,static_cast
我们可以创建一个帮助模板函数来从容器类型中推断出正确的定义:
辅助函数:
template< typename C >
inline auto overloaded_pred_for( const C&, bool ( *f )( const C& ) ) -> decltype( f )
{
return f;
}
它的用法示例:
std::all_of( vv.begin(), vv.end(),
overloaded_pred_for( std::vector< int >(), std::empty ) );
推荐阅读
- loops - 传单:遍历自定义标记的数据
- amazon-web-services - 为 www 网站设置重定向到非 www
- r - 如何显示具有条件的行的列
- javascript - 如何在一个范围内编写一些文本并通过使用 Selenium Python 3.7 按“ENTER”提交?
- javascript - REST API - 我了解响应缓存过程吗?(Node.js)
- python - RDD 分区问题
- angular - Angular Nativescript 路由导航给出错误
- webview - 在android 11(三星设备)的应用程序双重上运行时,Webview不会调用任何回调
- python - 什么是 x, y = func(x, y)
- list - Flutter Dart List - 如何检查列表是否包含对象