C++17的std::ptr_fun替代方法

33

我正在如下使用std::ptr_fun

static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}
这个答案中提到,然而这段代码在使用C++17(在Microsoft Visual Studio 2017上)时无法编译,会出现以下错误:
error C2039: 'ptr_fun': is not a member of 'std'

这个问题怎么能够解决?


2
错误是什么? - Lightness Races in Orbit
1
错误为:错误 C2039: 'ptr_fun':不是 'std' 的成员。 - user3717478
1
请在问题中编辑您的完整错误消息。 - Passer By
1
如果MVS2017支持,我认为你可以简单地执行std::not_fn(::isspace) - Holt
7个回答

66

您使用lambda:

static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c);}));
    return s;
}

你引用的答案来自2008年,早在C++11和lambda存在之前。


1
编译完美,比2008年的解决方案更易于理解。谢谢。 - user3717478
我冒昧地编辑了2008年的答案,并附上了链接到这个答案。 - SergeyA
2
@T.C. 我不明白 - std::isspace() 接受一个 int。如果将转换为 int 的操作放在 isspace() 中或者放在另一个仅调用 isspace() 的函数中,这有什么区别吗? - Barry
5
重点是你不应该使用 char 或者将 char 直接转换为 int 来调用任何 C 字符分类函数。你应该先将 char 转换为 unsigned char,再将其转换为 int。中间的 unsigned char 转换是必要的,以正确处理负值的 char - T.C.
5
@T.C. 这只是一个糟糕的界面而已。耶 C 语言。 - Barry
显示剩余6条评论

20

只需使用lambda:

[](unsigned char c){ return !std::isspace(c); }
请注意,我将参数类型更改为unsigned char,请参阅有关std::isspace的注释
自C++11起,std::ptr_fun已被弃用,并将在C++17中完全删除。

5
根据cppreferencestd::ptr_fun自C++11以来已被弃用,自C++17起已停止使用。
同样地,std::not1自C++17以来也已被弃用。
因此最好不要使用它们,而是使用lambda表达式(如其他答案中所解释的)。

4
我的回答与此主题中已经给出的回答相似。但是,与其使用“

”来结束段落,我建议在需要换行时使用“
”。这样做可以避免一些显示上的问题,因为有些浏览器并不总是识别“

”。
int isspace(int c);

我建议使用标准C库中的函数。

bool isspace(char c, const locale& loc);

标准的C++库提供了函数实例化(http://en.cppreference.com/w/cpp/locale/isspace),更加类型正确。在这种情况下,您不需要考虑char -> unsigned char -> int转换以及当前用户的语言环境。

搜索非空格的lambda表达式将如下所示:

[](char c) { return !std::isspace(c, std::locale::classic()); }

ltrim函数的完整代码如下:

static inline std::string& ltrim(std::string& s) {
    auto is_not_space = [](char c) { return !std::isspace(c, std::locale::classic()); };
    auto first_non_space = std::find_if(s.begin(), s.end(), is_not_space);
    s.erase(s.begin(), first_non_space);
    return s;
}

4

或者你可以使用std::not_fn

static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
        std::not_fn(static_cast<int(*)(int)>(std::isspace))));
    return s;
}

1
您可以像Nicol Bolas建议的那样使用Lambda,但是您也可以使用auto,并且类型将在那里被推导,如下所示:
    static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](auto c) {return 
       !std::isspace(c);}));
    return s;
  }

0

使用lambda表达式代替std::ptr_fun来配合std::isspace函数。

static inline std::string &ltrim(std::string &s) {
    str.erase(str.begin(), std::find_if(str.begin(), str.end(),
    [](unsigned char c) { return !std::isspace(c);}));
    return s;
}

您可以在std::isspace中找到更多详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接