【问题标题】:How to use isnan as a predicate function to std::find_if (c++11)如何使用 isnan 作为 std::find_if (c++11) 的谓词函数
【发布时间】:2013-07-10 15:07:33
【问题描述】:

我有一段代码在 std::vector<double> cats 上运行,并且正在执行以下操作:

std::find_if(cats.begin(), cats.end(), std::isnan<double>);

这在 4.3 之前的 gcc 下编译,但不再使用 gcc 4.7.2 编译。我收到这样的错误:

error: no matching function for call to 'find_if(std::vector<double>::iterator, std::vector<double::iterator, <unresolved overloaded function type>)'

我怎样才能让它在较新的 gcc 下编译?而且最好也在旧的gcc下?当然,无需摆脱 stl 并手动编写循环。如果两者都做不到,那么新的 gcc 就足够了,我会将这两个实现都留在那里,并带有 #define

【问题讨论】:

  • std::isnan&lt;double&gt;??在 C++11 标准中,isnan 是一个非模板函数。在 C99 中它是一个宏。
  • 我确实读过,但它以某种方式编译
  • 它曾经是 GCC 早期版本中的模板。在 GCC 4.7 中有三个重载一个整数类型的模板

标签: c++ c++11 gcc4.7


【解决方案1】:

您真正想要的重载不是 GCC 4.7 中的模板,它只是具有此签名的普通函数:

bool isnan(double);

(有一个模板,但是SFINAE意味着它只适用于整数类型。)

但在以前的版本中,它是一个模板,因此没有一种简单的可移植方式来获取其地址。

既然你说的是 C++11,你可以使用 lambda 并让 lambda 的主体进行重载解析以找到正确的重载(或模板特化):

std::find_if( cats.begin(), cats.end(), [](double d) { return std::isnan(d); } );

否则对于 C++03,您可以提供自己的转发包装器:

struct IsNan {
  double operator()(double d) const { return std::isnan(d); }
};
std::find_if( cats.begin(), cats.end(), IsNan() );

【讨论】:

  • 非常好!我想知道是否有一行代码可以同时编译?
  • 有趣,在 gcc 4.7.2 下给出“错误:没有上下文类型信息的重载函数”
  • 演员表也适用于模板(假设签名正确:bool (*)(double))。
  • @DavidRodríguez-dribeas,哦,难怪我使用演员表的测试不起作用!不幸的是,在 GCC 4.1 中它返回 int 所以演员仍然不是真正可移植的
  • 是的,由于 int bool 的原因,演员表似乎不便携。因此,如果我不想用随机转发包装器乱扔代码,我将需要两行不同的代码,具体取决于编译器。
【解决方案2】:

在 C++11 中,isnan 是一组针对不同浮点类型 floatdoublelong double 的三个重载。您可以使用强制转换语法解决您想要的重载:

std::find_if(cats.begin(), cats.end(),
             static_cast<bool (*)(double)>(std::isnan));

当然,如果您的目标平台都支持 lambda,那么 Jonathan 建议的 lambda 的使用对维护者来说可能更清楚。

【讨论】:

  • 此转换适用于 gcc 4.7.2,但在 4.1.2 下它给出了“错误:从类型 '' 到类型 'bool (*)(double)' 的无效 static_cast”
  • 那是我的第一次尝试,但我愚蠢地把返回类型弄错了,在 GCC 4.1 的&lt;cmath&gt; 中它返回了int
  • @JonathanWakely:哎呀......所以它有 C99 签名。所以也不是很便携。
猜你喜欢
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2018-09-21
  • 2018-07-26
  • 1970-01-01
相关资源
最近更新 更多