模板类型推导失败(std :: empty作为谓词) [英] template type deduction failing (std::empty as a predicate)

查看:74
本文介绍了模板类型推导失败(std :: empty作为谓词)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个向量向量,我想检查一下它们是否都是空的。使用标准库,我尝试过:

I have a vector of vectors, and I want to check if all of them are empty. Using the standard library, I tried:

#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'

/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/stl_algo.h:508:5: note: candidate template ignored: couldn't infer template argument '_Predicate'

由于类型推导的规则,我认为这是一种标准行为。但是无论如何,我最简单的解决方法是什么?

I guess it's a standard behavior, due to the rules of type deduction. But anyway, what i the easiest way to workaround this?

编辑:我接受rubenvb的回答,因为他给出了一个简单合理的解释以及自然的解决方法。 all_of接受谓词,该谓词可以是函数,函数对象或lambda表达式。 std :: empty都不是这些,而是​​功能模板。当显式实例化它时,我们得到一个应该起作用的普通函数。令人惊讶的是,它在我尝试过的大多数编译器上仍未编译。

I accepted rubenvb's answer, because he gave a simple and reasonable explanation, together with the natural workaround. all_of accepts a predicate, which is a function, a function object or a lambda expression. std::empty is neither of those, but a function template. When explicitly instantiating it, we get a plain function which should work. Surprisingly, it's still not compile on most compilers I tried.

好吧,让我们看看:

在GCC 6.3上,它编译就很好- https://godbolt.org/g/Pxta7C

on GCC 6.3, it compiles just fine - https://godbolt.org/g/Pxta7C

,但是在主干的GCC上,它会导致内部编译器错误- https:/ /godbolt.org/g/H6DHt5

but on GCC from trunk, it causes an internal compiler error - https://godbolt.org/g/H6DHt5

trunk或MSVC 2017中的Clang都无法成功编译它:

Neither Clang from trunk or MSVC 2017 succeed to compile it:

https://godbolt.org/g/819pbQ (C语)

https://godbolt.org/g/ua5E8e (MSVC)

EDIT2:显然,Robert Andrzejuk也是正确的:编译器无法处理它的原因是模棱两可的重载解决方案。 std :: empty具有3个不同的重载。其中两个是同样不错的候选者:通用的一个和std :: initializer列出的一个。我使用以下最小版本获得了类似的结果:

Apparently, Robert Andrzejuk is right too: the reason that the compiler cannot handle it is an ambiguous overload resolution. std::empty has 3 different overloads. and two of them are equally well candidates: the general one and the std::initializer list one. I achieved similar results with the following minimal version:

#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)。

There is one difference, though. This example simply not compile in GCC from trunk (instead of causing an ICE).

推荐答案

不幸的是,有一个问题来区分重载的模板函数为 std :: all_of 也是模板函数。更好的解释: std :: function无法区分重载函数

Unfortunately there is a problem to distinguish overloaded template functions as std::all_of is also a template function. Better explaination: std::function fails to distinguish overloaded functions

为此,请对正确的函数类型使用 static_cast bool(*)(const std :: vector< int>&)是必需的:

So to do this, a static_cast to the correct function type: bool ( * )( const std::vector< int >& ) is required:

std::all_of( vv.begin(), vv.end(),
             static_cast< bool ( * )( const std::vector< int >& ) >( std::empty ) );






使用有关必需的 static_cast 我们可以创建一个帮助器模板函数,以从容器类型中推断出正确的定义:


Using knowledge about the required static_cast we can make a helper template function to deduce the correct definition from the container type:

帮助器函数:

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 ) );

这篇关于模板类型推导失败(std :: empty作为谓词)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆