【问题标题】:std::remove_if and std::isspace - compile-time errorstd::remove_if 和 std::isspace - 编译时错误
【发布时间】:2014-02-05 13:21:40
【问题描述】:

我有以下代码:

#include <algorithm>
#include <cctype>
#include <string>

int main()
{
    std::string str;
    str.erase(std::remove_if(str.begin(), str.end(), std::isspace), str.end());
}

MSVC-11.0 编译此代码没有任何错误,但 gcc 4.7.2 给我以下错误:

main.cpp: In function ‘int main()’:
main.cpp:8:66: error: no matching function for call to ‘remove_if(std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)’
main.cpp:8:66: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
                 from main.cpp:1:
/usr/include/c++/4.7/bits/stl_algo.h:1160:5: note: template<class _FIter, class _Predicate> _FIter std::remove_if(_FIter, _FIter, _Predicate)
/usr/include/c++/4.7/bits/stl_algo.h:1160:5: note:   template argument deduction/substitution failed:
main.cpp:8:66: note:   couldn't deduce template parameter ‘_Predicate’

我发现了this 的问题,但是根据cppreference,没有任何版本的这个函数接受两个参数。我也发现了this 问题,但根据 cppreference(是的,再次),我看到只有一个 std::isspace 函数重载。

谁是对的?我究竟做错了什么?我该如何解决?

【问题讨论】:

标签: c++ gcc g++


【解决方案1】:

another overload of std::isspace,所以你需要指定使用哪一个。一种简单的方法是使用 lambda(或者如果您不支持 C++11,则编写自己的单行函数):

std::remove_if(str.begin(), str.end(), 
               [](char c){ 
                  return std::isspace(static_cast<unsigned char>(c));
               });

【讨论】:

    【解决方案2】:

    std::isspace 是一个重载函数,尽管这两个重载位于不同的标头中。另请注意,您的代码可能会引入未定义的行为,因为只有0..UCHAR_MAX 范围内的值可以传递给std::isspace,而char 可能已签名。

    这里有一个解决方案:

    std::string str;
    auto f = [](unsigned char const c) { return std::isspace(c); };
    str.erase(std::remove_if(str.begin(), str.end(), f), str.end());
    

    【讨论】:

    • 是的,取值在 0 和 UCHAR_MAX 之间的 is* 与通常签名的 char 之间的不匹配真的很邪恶。使is* 函数基本无用。
    • @JanHudec:AFAIK char 的签名是一个实现细节。在我工作的地方,我们使用 gcc 开关来保证它是无符号的,我想其他编译器也可能支持这个选项......但是对于任何非 ASCII 的东西(在 Unicode 的世界中......哦,好吧)
    • @MatthieuM.:这是实现细节,但默认在所有编译器中都已签名,而函数仅适用于未签名。并且任何尝试可重用的代码都不能依赖编译器开关。
    • @MatthieuM.: 其实正确的方式好像是std::isspace(std::char_traits&lt;char&gt;::to_int_type(c));此函数始终将char 转换为正整数,以便-1 保留用于eof。当然,在使用返回std::istream::traits_type::int_type的函数时不必这样做,因为流已经这样做了。
    • @JanHudec:很明显:/ C++ 需要对其字符处理进行彻底的改革,这表明它是在 Unicode 被炒作之前创建的。
    【解决方案3】:

    以下解决方案应该可以解决编译时错误:

    str.erase(std::remove_if(str.begin(), str.end(), (int(*) (int)) std::isspace), str.end());
    

    【讨论】:

      【解决方案4】:

      C++ 11以后可以使用lamda函数(比较容易理解),见下图:

      string s = " 3/  2";
      
      auto isSpace = [](const unsigned char c) 
      {
          return std::isspace(c);
      };
      s.erase(remove_if(s.begin(), s.end(), isSpace), s.end());
      

      输出:

      3/2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-08
        • 2015-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-23
        • 2014-08-07
        • 2015-01-04
        相关资源
        最近更新 更多