2

I have the following trim function

std::string trim(const std::string& str, std::function<bool(int ch)> isCharToTrim)
{
   auto trimmedStart = std::find_if_not(str.begin(), str.end(), isCharToTrim);
   if (trimmedStart == str.end())
   {
      return "";
   }
   else
   {
      auto trimmedEnd = std::find_if_not(str.rbegin(), str.rend(), isCharToTrim);
      return std::string(trimmedStart, trimmedEnd.base());
   }
}

When I pass std::isspace as second argument, it compiles with MSVC.
But I get an error with gcc: error: cannot resolve overloaded function 'isspace' based on conversion to type 'std::function<bool(int)>'.

Usage of the function that works on MSVC

const auto trimmed = trim(test, std::isspace);
const auto trimmed2 = trim(test, std::not_fn(std::isgraph));
const auto trimmed3 = trim(test, [](int ch) { return ch == ' '; });

What changes can I make to get it to compile on gcc? Change the argument type?

https://godbolt.org/z/81cjvrh7E

Synck
  • 2,727
  • 22
  • 20
  • 1
    Wrap the call in a lambda function. `std::isspace` returns an `int` that might be the reason for the problems. – john Jun 15 '22 at 09:31
  • 1
    You cannot take address of most std functions: -> wrap in lambda. (note also the pitfalls of [`std::isspace`](https://en.cppreference.com/w/cpp/string/byte/isspace) from the doc) – Jarod42 Jun 15 '22 at 09:31
  • there is a `std::isspace` template, but thats not the one OP wants to pick. The duplicate is not the right one. – 463035818_is_not_an_ai Jun 15 '22 at 09:41
  • BTW you cannot use `std::isspace` (and the other `std::is...` functions) on a `char` sequence; they take an `int` argument whose numeric value is expected to come from an `unsigned char` (IOW, you have to cast your `char` to `unsigned char` before calling `std::isspace`). See https://stackoverflow.com/a/45007070/214671 – Matteo Italia Jun 15 '22 at 09:53

1 Answers1

2

You should not use function pointers to functions in the standard library unless they are explicitly addressable functions.

You can wrap them in a lambda:

const auto trimmed = trim(test, [](auto c) { return std::isspace(static_cast<unsigned char>(c)); });

Note that it is not necessary to convert all callables to std::function just to call them or pass them to an algorithm. You can accept any callable by making the function a template:

 template <typename C>
 std::string trim(const std::string& str, C isCharToTrim);

The error complains about an overload because there is https://en.cppreference.com/w/cpp/locale/isspace in addition to the function you want to pass. Anyhow, strictly speaking the standard merely specifies what happens when you call std::isspace(int). There needs not actually be a function int std::isspace(int), it could be int std::isspace(int,int=42). There can be other overloads present. For this (and perhaps other) reasons it is generally not allowed to take pointers to standard functions.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185