Edgar Hernandez
Edgar Hernandez

Reputation: 425

std::ostream recognize without defining header

I created this code:

Main.cpp

#include <iostream>
#include "Quote.h"

int main()
{
    derived().print(std::cout);

    getchar();
    return 0;
}

Quote.h

#pragma once
#include <string>

class base {
public:
    std::string name() { return basename; }
    virtual void print(std::ostream &os) { os << basename; }

private:
    std::string basename = "abc";
};

class derived : public base {
public:
    void print(std::ostream &os) { base::print(os); os << " " << i; }

private:
    int i = 0;
};

If I don't include the iostream header file in Main.cpp, as expected, std::cout is not recognized. My question is: Why there's no problem with the use of std::ostream in Quote.h if iostream is not included?. Either cout as ostream are defined in the aforementioned library, why the cout use is a problem and ostream not?

I'm using VS 2017, in case this info is important.

Upvotes: 4

Views: 1026

Answers (5)

Andriy Tylychko
Andriy Tylychko

Reputation: 16286

All existing answers concentrate on #include <string>. I'd like to point at another side. Consider slightly modified version:

quote.h:

#pragma once

// uncomment to get an analog of original example
// #include <string>

struct Quote {};

std::ostream& operator<<(std::ostream& os, Quote const&)
{
    return os << "quote\n";
}

main.cpp:

#include <iostream>
#include "quote.h"

int main()
{
    std::cout << Quote{};
}

As you see #include <string> is commented out, quote.h still doesn't include iostream and the program still compiles. It does because only source files (.cpp, or translation units) are directly compiled. Headers are literally included. Now if we literally include quote.h in main.cpp we get:

#include <iostream>

// uncomment to get an analog of original example
// #include <string>

struct Quote {};

std::ostream& operator<<(std::ostream& os, Quote const&)
{
    return os << "quote\n";
}

int main()
{
    std::cout << Quote{};
}

(online)

It's what actually gets compiled. Notice everything is alright here, #include <iostream> before std::ostream usage.

And as was correctly pointed in comment to another answer, this is an example why it's important to always maintain self-sufficient headers that include all headers they depend on.

As @Evgeny pointed out in the comment, please check recommendations about organising our includes.

Upvotes: 3

R Sahu
R Sahu

Reputation: 206727

Why there's no problem with the use of std::ostream in Quote.h if <iostream> is not included?

<iostream> get #included indirectly.

It's best not to rely on such indirection #includes. You can't count on it being true on all platforms. It may even change from debug build to release build.

When you want to use a class or a function, it's best to lookup the standard for the header that's supposed to provide the definition of the class and the declaration of the function, and #include the header directly in your file.

Upvotes: 1

Matteo Italia
Matteo Italia

Reputation: 126937

The header <string> provides the extraction and insertion operators for std::string, so it has to make sure that std::ostream is at least forward-declared; your code only uses a reference to ostream, for which a forward declaration suffices, plus the aforementioned insertion operator, which is correctly declared.

So, strictly speaking, all that is needed by your header is already provided by the header <string>, although I'd probably explicitly include <iosfwd> for clarity.

Upvotes: 1

FrankS101
FrankS101

Reputation: 2135

You include <string> in your header file. If you go to the string header you will see the first lines as (in VS2017):

// string standard header
#pragma once
#ifndef _STRING_
#define _STRING_
#ifndef RC_INVOKED
#include <istream> <----- here
#include <xstring_insert.h>

and going to the istream header:

// istream standard header
#pragma once
#ifndef _ISTREAM_
#define _ISTREAM_
#ifndef RC_INVOKED
#include <ostream> <-- here

which I think already answers your question. However, this is implementation dependent and you should not rely on this but include explicitly the iostream header.

Upvotes: 2

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154035

The header <string> declares an output operator using std::ostream. It seems the implementation you are using does so in a way making std::ostream generally available.

The C++ standard defines which headers make which declarations available at least. It doesn’t prohibit against additional names being made available. Different implementations may choose to not make the declarations available. I have tried making strictly only mandated declarations available in my implementation but this turns out to be not quite as simple as it sounds.

Upvotes: 2

Related Questions