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);
      |     ~~~~~~~~~~~~~~^~~~~~~
0

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Why does ::tolower work?
@user3882729 because single-character tolower is present in global namespacea as a C relict. Function from locale does not.
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.

2 Comments

I rather guess that the program is implicitly including <locale>, so that another version of toupper is in the std namespace. That seems to have been the cause in the duplicate question.
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.