3

I would like to understand why fully qualifying with std:: results in the compilation error below using std::transform.

#include <algorithm>
int main() {
    std::string str;
    std::transform(str.begin(), str.end(), str.begin(), std::tolower); // does not compile

    std::transform(str.begin(), str.end(), str.begin(), ::tolower); // OK
}

Error that it cannot deduce unary operator.

source>: In function 'int main()':
<source>:4:19: error: no matching function for call to 'transform(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
    4 |     std::transform(str.begin(), str.end(), str.begin(), std::tolower);
      |     ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/algorithm:62,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_algo.h:4285:5: note: candidate: 'template<class _IIter, class _OIter, class _UnaryOperation> constexpr _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation)'
 4285 |     transform(_InputIterator __first, _InputIterator __last,
      |     ^~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_algo.h:4285:5: note:   template argument deduction/substitution failed:
<source>:4:19: note:   couldn't deduce template parameter '_UnaryOperation'
    4 |     std::transform(str.begin(), str.end(), str.begin(), std::tolower);
      |     ~~~~~~~~~~~~~~^~~~~~~
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
user3882729
  • 1,339
  • 8
  • 11

2 Answers2

7

You need to specify, which one of tolower functions in std namespace you want:

std::transform(str.begin(), str.end(), str.begin(), static_cast<int(*)(int)>(std::tolower));

Note that you also missing string and cctype includes.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48
2

It is advised not to use std::tolower() with standard algorithms, as you need to first cast the input to unsigned char.

You could use an anonymous function as follows:

std::transform(str.begin(), str.end(), str.begin(), 
               [](unsigned char c){ return std::tolower(c); }
              );

Your code implicitly includes string header that probably includes C standard library headers that define basic character handling functions. That is why the version using ::tolower() compiles.

Dima Chubarov
  • 16,199
  • 6
  • 40
  • 76
  • I rather guess that the program is implicitly including ``, so that another version of `toupper` is in the `std` namespace. That seems to have been the cause in the duplicate question. – Andreas Wenzel Apr 01 '22 at 18:24
  • 1
    Also, `std::tolower` is one of the *non-addressable functions* (because it may be implemented as an intrinsic), so wrapping it in a lambda is double-plus-good, in addition to the `unsigned char`. – Eljay Apr 01 '22 at 18:26