0

I have a method to log with the following definition:

void log(std::string s) {
    std::string tag = "main";
    std::cout << tag << " :" << s << std::endl;
}

I'm trying to call this method like this:

log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));

direction and count are integers.

I'm getting this following error with << underlined in red:

no operator << matches these operands. operand types are const char [10] << std::string

I have #include<string> in my header to make sure my strings are working as they should.

I tried std::string("direction") and still the issue was same.

Beginner in C++. Help would be appreciated.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Faizuddin Mohammed
  • 4,118
  • 5
  • 27
  • 51

5 Answers5

2

Substitute the << with the + operator as you are manipulating the string, not the stream:

log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
Ron
  • 14,674
  • 4
  • 34
  • 47
2

operator<< isn't used for arbitrary string concatenation - it is called an "output stream operator", and it is only used in the context of std::ostream.

When you say...

std::cout << tag << " :" << s << std::endl;

...you're actually writing code roughly equivalent to:

std::cout.operator<<(tag).operator<<(" :").operator<<(s).operator<<(std::endl);

As you can see operator<< knows how to work with std::cout and std::string, but not between strings.


In order to concatenate std::string instances, you can simply use operator+:

log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));

Please note that this concatenation technique is not the most efficient: you might want to look into std::stringstream or simply use std::string::reserve to avoid unnecessary memory allocations.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Okay. But I just changed `<<` to `+` and I don't see that error anymore. Conversion still necessary? – Faizuddin Mohammed Sep 21 '17 at 09:28
  • @FaizuddinMohammed: yeah sorry, you don't actually need to convert `"direction"` to an `std::string` explicitly as `operator+` is defined for `(const char*, const std::string&)`. – Vittorio Romeo Sep 21 '17 at 09:34
0

If you're determined to use the operator<< notation you need an object that understands it.

Here's such an object (I make no claims that this is a good idea):

#include <string>
#include <sstream>
#include <iostream>

void log(std::string s) {
    std::string tag = "main";
    std::cout << tag << " :" << s << std::endl;
}

struct string_accumulator
{
    std::ostringstream ss;

    template<class T>
    friend string_accumulator& operator<<(string_accumulator& sa, T const& value)
    {
        sa.ss << value;
        return sa;
    }

    template<class T>
    friend string_accumulator& operator<<(string_accumulator&& sa, T const& value)
    {
        return operator<<(sa, value);
    }

    operator std::string () { return ss.str(); }
};

inline auto collect() -> string_accumulator
{
    return string_accumulator();
}

int main()
{
    int direction = 1;
    int count = 1;
    log(collect() << "direction" << std::to_string(direction) << ", count: " << std::to_string(count));
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • `std::ostringstream` is such an object and is standard – Basile Starynkevitch Sep 21 '17 at 09:33
  • you could also write a `std::string operator << (std::string, std::string)` if you don't want to use such an object ... I'm not suggesting it, but you can – UKMonkey Sep 21 '17 at 09:38
  • @BasileStarynkevitch that's why I used it :) – Richard Hodges Sep 21 '17 at 09:44
  • @UKMonkey apart from the whole "surprising behaviour in the global namespace" argument, you'd have difficulty when it came to io manipulators. This is why I've proxied the ostringstream. It also now by default understands everything in . – Richard Hodges Sep 21 '17 at 09:49
  • @RichardHodges ohh, I'm not at all suggesting that someone implement that operator, but it's just another way of having that syntax :) Even you in your answer said 'I make no claims this is a good idea' so I put another suggestion under the same heading – UKMonkey Sep 21 '17 at 09:51
0

The prototype of your function is void log(std::string s);. It awaits for an std::string. So you need to pass a string to it, not a stream!

So, change this:

log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));

to this:

log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));

where I only changed the << operator to + operator. It will now concatenate everything inside the parentheses to a single std::string.


Your attempt implies that you wanted to pass std::ostream as the parameter. Maybe you want to read C++ Passing ostream as parameter. However, if I were you, I would just overload <<.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
-2

why don't you use: // just include thisusing namespace std;