Can't std::ostream output a const char array?
Asked Answered
F

1

10

For the fun and experience of it, I'm modifying and exploring the source code for Blobby Volley 2 1.0 (Linux).

Well... I would be modifying the source code, but I can't even get the program to compile. (Sad, isn't it?)

Here's the code that causes the error:

std::ostream& operator<<(std::ostream& stream, const ServerInfo& val) {
    return stream << val.name << " (" << val.hostname << ":" << val.port << ")";
    }

Trying to compile this with g++ 5.4.0 gives the following (simplified output--the original output is ~443 lines) error message:

error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘const char [32]’)

return stream << val.name << " (" << val.hostname << ":" << val.port << ")";

I simplified the code to this:

std::ostream& operator<<(std::ostream& stream, const ServerInfo& val) {
    stream << "hello"; //can't get simpler than this, right?
    return stream;
    }

and got

error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘const char [6]’)

stream << "hello";

The code that calls it looks like this:

std::cout << "duplicate server entry\n";
std::cout << info << "\n"; //it's called here

The thing I find most surprising is that we all know that std::cout and its ilk can handle char arrays.

For instance,

#include <iostream>
#include <string>

int main () {
    const char a[6] = "hello";
    std::cout << a << std::endl; //No problem here!
    return 0;
    }

works without a hitch.


Oh, one more thing.

If I include <string>, this works:

std::ostream& operator<<(std::ostream& stream, const ServerInfo& val) {
    stream << std::string("hello");
    return stream;
    }

Does anyone know what I'm missing?


PS: Here's a pastebin of the errors.

PPS: Here's the headers that were requested:

/* header include */
#include "NetworkMessage.h"

/* includes */
#include <cstring>

#include "UserConfig.h"
#include "SpeedController.h"

PPS: If you are wondering why I didn't get an error about std::ostream not being defined, check the 3rd paragraph of Sam's answer.

Freehanded answered 30/8, 2016 at 2:42 Comment(18)
Can you post, in addition to what you have here, the full error log? There might be something else in there that's important.Wallpaper
@templatetypedef: Are you positive you want it all?Freehanded
You're reporting an error that shouldn't normally be happening, so I suspect something else might be up as well. So... yes! :-)Wallpaper
The most likely answer is that the translation unit in question is missing an include of <iostream>.Layamon
@templatetypedef: I'm getting you your error log. I have to format it first so that you can actually read it though... :DFreehanded
@JefréN.: Post the headers as well which you have included in the file which contains this code.Indult
@templatetypedef: Posted pastebin.Freehanded
Sure looks like the errors you get if you didn't #include <iostream> - the only overload it knows about is the custom one you wrote.Wallpaper
@templatetypedef: I'll try it, although I don't think it is theoretically necessary.Freehanded
@templatetypedef: That was the problem ... Stunned. Post it as an answer and I'll accept it, if you want.Freehanded
Give credit to @SamVarshavchik - he was the first to figure that out. :-)Wallpaper
@SamVarshavchik: Congratulations! You're hypothesis proved correct. Do you care to give it as an answer? (Since iostream was included in 'main.cpp', I'm still not sure why it was necessary, though.)Freehanded
@Wallpaper and everyone else: Thanks for the help and brainstorming. I guess I just learned another lesson in never assuming. :DDFreehanded
Every C++ file is compiled independently of all others, so just because you included a header in one file doesn't mean you've included it everywhere.Wallpaper
Anyone think I should delete this question?Freehanded
@templatetypedef: In truth, I include every header I need in each file. However, I didn't think it was strictly necessary. Guess it is. Thanks again for the help and explanation. :DFreehanded
@JefréN. Deleting the question now would probably save reviewers' work in the long run, since I suspect that's the ultimate fate of this question anyways. But it's up to you. Glad you figured it out though.Empyrean
@JasonC: If not for the fact that Sam Varshavchik, the guy who initially guessed what the problem was, gave an answer like I asked him to, I would delete the question. But as it is, I think I'm gonna let stackoverflow take its course ... :DFreehanded
L
23

The fact that #include <iostream> was likely missing was deduced using the Sherlock Holmes approach to debugging: "when you have eliminated the impossible, whatever remains, however improbable, must be the truth".

Clearly. std::ostream should've have had no problems accepting a const char * overload.

Therefore, an overload resolution complaint must mean that <iostream> wasn't included. Most C++ library classes are forward-declared all over the place. Including some random header file is likely to get you a forward declaration of std::ostream, as a free bonus. So the compiler will not complain about this class not being defined.

But unless <iostream> is included, the compiler will not know about all the overloads that are defined there. That's it.

Layamon answered 30/8, 2016 at 10:53 Comment(1)
#include <ostream> (which declares the const char* overload - 27.7.3.1) would suffice instead of iostream (which includes ostream - 27.4.1).Marion

© 2022 - 2024 — McMap. All rights reserved.