Node.JS
Node.JS

Reputation: 1592

Convert normal iterator of characters to string

I am wondering how to convert iterator of characters __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> > to string in C++?

#include <iostream>
#include <string>
#include <algorithm>
using std::string;

#define TO_UPPER(s) (transform((s).begin(), (s).end(), (s).begin(), ::toupper))
#define TO_LOWER(s) (transform((s).begin(), (s).end(), (s).begin(), ::tolower))


int main() {
    string str = "Hello world!";

    string result = TO_LOWER(str);

    std::cout << result << std::endl;
    return 0;
}

Error:

[1/2] Building CXX object CMakeFiles/untitled.dir/main.cpp.o
FAILED: CMakeFiles/untitled.dir/main.cpp.o 
/usr/bin/c++   -g -std=gnu++11 -MD -MT CMakeFiles/untitled.dir/main.cpp.o -MF CMakeFiles/untitled.dir/main.cpp.o.d -o CMakeFiles/untitled.dir/main.cpp.o -c /home/amir-pc/CLionProjects/untitled/main.cpp
/home/amir-pc/CLionProjects/untitled/main.cpp: In function ‘int main()’:
/home/amir-pc/CLionProjects/untitled/main.cpp:7:31: error: conversion from ‘__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >’ to non-scalar type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} requested
    7 | #define TO_LOWER(s) (transform((s).begin(), (s).end(), (s).begin(), ::tolower))
      |                     ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/amir-pc/CLionProjects/untitled/main.cpp:13:21: note: in expansion of macro ‘TO_LOWER’
   13 |     string result = TO_LOWER(str);
      |                     ^~~~~~~~
ninja: build stopped: subcommand failed.

Upvotes: 1

Views: 412

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311088

These macros change the string in place

#define TO_UPPER(s) (transform((s).begin(), (s).end(), (s).begin(), ::toupper))
#define TO_LOWER(s) (transform((s).begin(), (s).end(), (s).begin(), ::tolower))

So just write

TO_LOWER(str);
std::cout << str << std::endl;

Otherwise write

#include <iterator>

//...

string str = "Hello world!";

string result;
result.reserve( str.size() );

std::transform( str.begin(), str.end(), std::back_inserter( result ), ::tolower );

std::cout << result << std::endl;

Pay attention to that it is a bad idea to use such macros. At least you could declare inline functions.

Upvotes: 0

HolyBlackCat
HolyBlackCat

Reputation: 96886

std::transform modifies the container in place. You don't need its return value, you can just read the original container.

Also avoid using macros if possible. Prefer functions.

Also note that std::toupper causes undefined behavior if given a negative character code. You need to cast the parameter to unsigned char first to avoid this.

Here's a good implementation from cppreference:

std::string str_toupper(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), 
                // static_cast<int(*)(int)>(std::toupper)         // wrong
                // [](int c){ return std::toupper(c); }           // wrong
                // [](char c){ return std::toupper(c); }          // wrong
                   [](unsigned char c){ return std::toupper(c); } // correct
                  );
    return s;
}

Upvotes: 7

Related Questions