1

I want to replace my buffer string from a value of "eof" to "\0" using std::replace.

std::string buffer = "eof";
std::replace(buffer.begin(), buffer.end(), std::string("eof"), std::string("\0"));

Compiler error :

no match for ‘operator==’ (operand types are ‘char’ and ‘const std::__cxx11::basic_string<char>’)
  • 5
    [`std::replace`](https://en.cppreference.com/w/cpp/algorithm/replace) takes *single element* to replace from and to. – MikeCAT Jul 22 '22 at 15:42
  • 3
    Perhaps you should use [`std::string::replace`](https://en.cppreference.com/w/cpp/string/basic_string/replace) instead? – Some programmer dude Jul 22 '22 at 15:47
  • 1
    Note that `"\0"` is treated as `""`, is that what you really want? Do you want to replace `"eof"` with a blank string? If so, then just use `""` (or even just `string{}`). But, if you want to replace `"eof"` with an actual `'\0'` nul character, then you need to use `std::string("\0", 1)` instead. – Remy Lebeau Jul 22 '22 at 18:03

2 Answers2

0

The problem is that internally std::replace checks == on *first and old_value where first is the first argument passed(iterator here) and old_value is the third argument passed shown in the below possible implementation:

template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last,
             const T& old_value, const T& new_value)
{
    for (; first != last; ++first) {
//----------vvvvvv    vvvvvvvvv--------->compares *first with old_value
        if (*first == old_value) {
            *first = new_value;
        }
    }
}

Now *first is char and old_value(and new_value) is std::string in our example and since there is no operator== for checking if a char and a std::string are equal and also as there is no implicit conversion between the two, we get the mentioned error.

One way to solve this is to use std::string::replace. More alternatives can be found at : Replace substring with another substring C++

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Why is the Forward Iterator (first) a char though? –  Jul 22 '22 at 15:59
  • 1
    @apetrai Because we passed the first argument `buffer.begin()` which is of `std::string::iterator`. This means `first` is of type `std::string::iterator`. And thus when you dereference `first` like `*first` we get `char` as a `std::string` consists of `char` elements. In other words, dereferencing the iterator gives us the element inside the container. Just to give you an analogy suppose we had a `vector` then we would have gotten `*first` as `int`. – Jason Jul 22 '22 at 16:02
  • 1
    Thank you very much. You're very good at explaining answers. –  Jul 22 '22 at 16:04
  • @apetrai In other words, dereferencing the iterator(like `*first`) gives us the element inside the container which in case of `std::string` is nothing but `char`. – Jason Jul 22 '22 at 16:04
0

You can use std::string::replace, if you intention is to replace all occurences of eof substring with \0 then I suggest using standard method as in:

https://en.cppreference.com/w/cpp/string/basic_string/replace

std::size_t replace_all(std::string& inout, std::string_view what, std::string_view with)
{
    std::size_t count{};
    for (std::string::size_type pos{};
         inout.npos != (pos = inout.find(what.data(), pos, what.length()));
         pos += with.length(), ++count) {
        inout.replace(pos, what.length(), with.data(), with.length());
    }
    return count;
}

Your code should look as follows:

std::string buffer = "eof";
replace_all(buffer, "eof", "\0");

https://coliru.stacked-crooked.com/a/4110765b0f265aae

marcinj
  • 48,511
  • 9
  • 79
  • 100