Forward-declaring library names - c++

An excerpt from "Exceptional C++":
"In the old days, you could just replace "#include " with "class ostream;" in this situation, because ostream used to be a class and it wasn't in namespace std. Alas, no more. Writing "class ostream;" is illegal for two reasons:
ostream is now in namespace std, and programmers aren't allowed to declare anything that lives in namespace std.
ostream is now a typedef of a template; specifically, it's typedef'd as basic_ostream. Not only would the basic_ostream template be messy to forward-declare in any case, but you couldn't reliably forward-declare it at all, because library implementations are allowed to do things like add their own extra template parameters (beyond those required by the standard), which, of course, your code wouldn't know about—one of the primary reasons for the rule that programmers aren't allowed to write their own declarations for things in namespace std."
My question:
I don't understand the part marked in bolds.
Thanks,

The part in bolds just says you can't forward declare ostream like this:
class ostream;
because ostream now is a typedef, and the details of declaration may or may not vary on different implementations.
because programmers are not allowed to declare anything in namespace std (though it will work on the majority of compilers).
If you want a forward declaration of ostream, include <iosfwd> instead. (Or look inside what it looks like for your implementation).

You can, if you are OK with the fact, that it will only work for a specific version of a specific compiler. It will be ugly, but you can do it (you can pretty much copy the content of the header into your code, and it will still work).
The reason why you shouldn't is exactly why it is in the header. You want to use some external interface and don't want to care about the compiler internals. The compiler guarantees you the external interface. As for the implementation, that's the compilers choice.

Related

Why does C++ forbid forward declarations of non-template std:: types?

The C++ standard does not allow code to forward declare classes in namespace std, even when they are not templates.
I see no good reason to do this, so I wonder what is the motivation?
It could be a huge compile time improvement. For example std::mutex is a simple class, but the <mutex> header drags in a ton of stuff (at least on my implementation).
If somebody wonders why I am making a distinction between templates and non-templates, then it is because template instantiations can differ significantly based on what template arguments are provided, so I guess that might be trickier to implement/support.
for example std::mutex is a simple class
How do you know? The standard describes it as a class, but nothing is stopping an implementer from doing
namespace std {
using mutex = _Internal_detail::_PthreadMutex;
}
Granted, I omitted some (likely very verbose and expert friendly) checks for when this alias should be set. But this is a valid implementation technique!
Now if you add your forward declaration, you will get an error since an alias and a class are different things. That makes such forward declarations inherently non-portable, and as such, they are deemed to produce undefined behavior.

how to forward-declare std::set in c++?

To speed up the compiling process, I'm trying to simplify my header file MyClass.hpp by forward-declaring STL containers such as std::vector, std::set...
But std::set can NOT be forward-declared within following codes, while std::vector can be.
namespace std {
template<typename T, typename A> class vector;
template<typename T, typename C, typename A> class set;
};
class MyClass_t {
void showVector( std::vector<int>& );
void showSet( std::set<int>& );
}
As we known, the header <set> is very long and complicated. If we add #include <set> into MyClass.hpp, in fact every translation units that uses MyClass_t have to include implicitly the header <set>. But I think that it's not necessary, because not every translation units using MyClass_t will call MyClass_t::showSet, so I think the simplification makes sense.
How to do it?
Thanks in advance, pls forgive my poor English.
One of the purposes of namespaces is to separate code that comes from different sources. This is often thought of avoiding name conflicts, but it goes to a deeper level.
When a library defines a namespace, it (typically) claims total possession of it. The library reserves the right to change any and all aspects of everything defined in the namespace, usually guaranteeing only the public API. This extends to forward declarations. Any forward declarations in the namespace are the library's domain unless stated otherwise, as the library may want to change things behind the scenes. Some libraries take this seriously and provide forward-declaration headers, but without those, you are out of luck.
In general, do not expect to be able to forward declare anything you do not control. Even if it works initially, it is liable to break at any upgrade/patch to the library.
Moving on to std::set, the std namespace is reserved for the standard library. The standard library grants you the ability to declare a few things in the std namespace in restricted circumstances, but otherwise it is off-limits to you. Unfortunately for your goal, the standard library does not require forward-declaration headers. If you want your code to be cross-platform and/or stable after a compiler upgrade, you will need to include the full header.
Going on a tangent: this is the basis for specifying that adding your own definitions to namespace std is undefined behavior. It's not that such things are guaranteed to break something, but that the language standard cannot guarantee what exactly will break things. (Realistically, if you were to define a class named supercalifragilisticiwillmisspellthis in namespace std, probably nothing will blow up.) To keep things simple, the "undefined behavior" label is applied and implementations are given maximum freedom.

Why does Google Style Guide discourage forward declaration?

Not to say that the Google Style Guide is the holy bible but as a newbie programmer, it seems like a good reference.
The Google Style Guide lists the following disadvantages of forward declaration
Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.
A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates can prevent the header owners from making otherwise-compatible changes to their APIs, such as widening a parameter type, adding a template parameter with a default value, or migrating to a new namespace.
Forward declaring symbols from namespace std:: yields undefined behavior.
It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:
Code:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
If the #include was replaced with forward decls for B and D, test() would call f(void*).
Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.
Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex.
However, some search on SO seemed to suggest that forward declaration is universally a better solution.
So given these seemingly non-trivial disadvantages, can someone explain this discrepancy?
And when is it safe to ignore some or all of these disadvantages?
some search on SO seemed to suggest that forward declaration is
universally a better solution.
I don't think that's what SO says. The text you quote is comparing a "guerilla" forward declaration against including the proper include file. I don't think you'll find a lot of support on SO for the approach Google is criticising here. That bad approach is, "no, don't #include include files, just write declarations for the few functions and types you want to use".
The proper include file will still contain forward declarations of its own, and a search on SO will suggest that this is the right thing to do, so I see where you got the idea that SO is in favour of declarations. But Google isn't saying that a library's own include file shouldn't contain forward declarations, it's saying that you shouldn't go rogue and write your own forward declaration for each function or type you want to use.
If you #include the right include file, and your build chain works, then the dependency isn't hidden and the rest of the problems mostly don't apply, despite the fact that the include file contains declarations. There are still some difficulties, but that's not what Google is talking about here.
Looking in particular at forward declarations of types as compared with class definitions for them, (4) gives an example of that going wrong (since a forward declaration of D cannot express that it's derived from B, for that you need the class definition). There's also a technique called "Pimpl" that does make careful use of a forward type declaration for a particular purpose. So again you'll see some support on SO for that, but this isn't the same as supporting the idea that everyone should in general run around forward-declaring classes instead of #includeing their header files.
From Titus Winters' CppCon 2014 talk:
The big one that we've learned lately is: Forward declaring anything with a template in it is a really bad idea. This led to maintenance problems like you would not believe. Forward declaration may be okay, in some cases? My suspicion is the rule is actually going to change to: Library owners are encouraged to provide a header that specifically forward declares the things that they think are worth it (emphasis added), and you probably shouldn't forward declare yourself, and nobody should ever forward declare a templated type. We'll see. We're still working out the [inaudible] details from what we've learned.
So maybe issues with trying to directly forward declare templated types might be one of their motives for discouraging forward declaration wholesale...?
Also, providing "a header that specifically forward declares the things that they think are worth it" sounds similar to the way <iosfwd> is used, as described here (Solution 2.2), here, and here.
EDIT:
To be clear, I wasn't saying I agree or disagree with Google's discouragement of forward declaration. I was just trying to understand their rationale, and made an aside/observation about <iosfwd>.
Personally, I use forward declarations whenever I can, following the guideline stated later in that same GOTW linked above (Solution 3):
Guideline: Never #include a header when a forward declaration will suffice.
but Winters' reasoning seems to have some merit as well. I've worked on code where I forward declared templated types from a third party library, and the syntax does get messy (I haven't yet run into the maintenance problems Winters alluded to). OTOH, I'm not so sure about discouraging all forward declarations as stated in the Google C++ Style Guide, but I guess that's what works for Google?
Disclaimer: I'm no expert, still learning.

Why is there no <stlfwd> header and can the non-existence of it be considered a defect?

The standard library includes an <iosfwd> header, that (forward) declares all streams including any typedefs and defines the char_traits template, including the specializations.
Sadly, there is no such <stlfwd> header that (forward) declares all the common STL datatypes and functions like vector, map, less, sort, etc. Even more sadly, user code is not allowed to add such declarations / typedefs to the std namespace, as per
§17.4.3.1 [lib.reserved.names] p1:
It is undefined for a C + + program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std.
Yep, that covers the case of (forward) declarations, even if the types already exist in the standard library. Of course, most (all?) compilers will behave perfectly normal even if one adds such declarations, but strictly and language lawyer speaking, it is undefined behaviour. I find this especially tedious for typedefing standard containers, like:
// how to forward declare map and string?
typedef std::map<std::string, std::string> Attributes;
Now, can this be considered a defect?
I mean both the non-existence of a <stlfwd> header (or better, <stdfwd>, covering <iosfwd> too) and the ban on declarations already existing in the standard library.
Also, according to this question, if one (forward) declares the standard container, algorithms and functors / functionals exactly as demanded by the standard, the code should be perfectly valid (if it weren't for the ban of user-made declarations in the std namespace), because implementations aren't allowed to add any hidden/defaulted template parameters.
I am asking this because I'm thinking of eventually submitting a defect report regarding this.
What would be the purpose of forward declaring say less or sort or really any other algorithm? If you're passing a general purpose algorithm around it will almost certainly be as a template type and not need a forward declaration at all.
That leaves us with the container types. There are definitely cases where forward declarations of them would be useful but I suspect that it was simply decided that as each container definition is relatively simple (compared to iostreams) it would be preferable to just use the full include rather than a <containerfwd> include for example.

Should every class have its own namespace?

Something that has been troubling me for a while:
The current wisdom is that types should be kept in a namespace that only
contains functions which are part of the type's non-member interface (see C++ Coding Standards Sutter and Alexandrescu or here) to prevent ADL pulling in unrelated definitions.
Does this imply that all classes must have a namespace of their own? If
we assume that a class may be augmented in the future by the addition of
non-member functions, then it can never be safe to put two types in the
same namespace as either one of them may introduce non-member functions
that could interfere with the other.
The reason I ask is that namespaces are becoming cumbersome for me. I'm
writing a header-only library and I find myself using classes names such as
project::component::class_name::class_name. Their implementations call
helper functions but as these can't be in the same namespace they also have
to be fully qualified!
Edit:
Several answers have suggested that C++ namespaces are simply a mechanism for avoiding name clashes. This is not so. In C++ functions that take a parameter are resolved using Argument Dependent Lookup. This means that when the compiler tries to find a function definition that matches the function name it will look at every function in the same namespace(s) as the type(s) of its parameter(s) when finding candidates.
This can have unintended, unpleasant consequences as detailed in A Modest Proposal: Fixing ADL. Sutter and Alexandrescu's rule states never put a function in the same namespace as a class unless it is meant to be part of the interface of that class. I don't see how I can obey that rule unless I'm prepared to give every class its own namespace.
More suggestions very welcome!
No. I have never heard that convention. Usually each library has its own namespace, and if that library has multiple different modules (e.g. different logical units that differ in functionality), then those might have their own namespace, although one namespace per library is sufficient. Within the library or module namespace, you might use namespace detail or an anonymous namespace to store implementation details. Using one namespace per class is, IMHO, complete overkill. I would definitely shy away from that. At the same time, I would strongly to urge you to have at least one namespace for your library and put everything within that one namespace or a sub-namespace thereof to avoid name clashes with other libraries.
To make this more concrete, allow me to use the venerable Boost C++ Libraries as an example. All of the elements within boost reside in boost::. There are some modules within Boost, such as the interprocess library that have its own namespace such as boost::interprocess::, but for the most part, elements of boost (especially those used very frequently and across modules) simply reside in boost::. If you look within boost, it frequently uses boost::detail or boost::name_of_module::detail for storing implementation details for the given namespace. I suggest you model your namespaces in that way.
No, no and a thousand times no! Namespaces in C++ are not architectural or design elements. They are simply a mechanism for preventing name clashes. If in practice you don't have name clashes, you don't need namespaces.
To avoid ADL, you need only two namespaces: one with all your classes, and the other with all your loose functions. ADL is definitely not a good reason for every class to have its own namespace.
Now, if you want some functions to be found via ADL, you might want to make a namespace for that purpose. But it's still quite unlikely that you'd actually need a separate namespace per class to avoid ADL collisions.
Probably not. See Eric Lippert's post on the subject.
Couple things here:
Eric Lippert is a C# designer, but what he's saying about bad hierarchical design applies here.
A lot of what is being described in that article has to do with naming your class the same thing as a namespace in C#, but many of the same pitfalls apply to C++.
You can save on some of the typedef pain by using typedefs but that's of course only a band-aid.
It's quite an interesting paper, but then given the authors there was a good chance it would be. However, I note that the problem concerns mostly:
typedef, because they only introduce an alias and not a new type
templates
If I do:
namespace foo
{
class Bar;
void copy(const Bar&, Bar&, std::string);
}
And invoke it:
#include <algorithms>
#include "foo/bar.h"
int main(int argc, char* argv[])
{
Bar source; Bar dest;
std::string parameter;
copy(source, dest, parameter);
}
Then it should pick foo::copy. In fact it will consider both foo::copy and std::copy but foo::copy not being template will be given priority.