how to forward-declare std::set in c++? - 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.

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.

STL Extension/Modification Best Practice

I have been writing in c++ for a few months, and i am comfortable enough with it now to begin implementing my own library, consisting of things that i have found myself reusing again and again. One thing that nagged me was the fact that you always had to provide a beginning and end iterator for functions like std::accumulate,std::fill etc...
The option to provide a qualified container was completely absent and it was simply an annoyance to write begin and end over and over. So, I decided to add this functionality to my library, but i came across problem, i couldn't figure out the best approach of doing so. Here were my general solutions:
1. Macros
- A macro that encapsulates an entire function call
ex. QUICK_STL(FCall)
- A macro that takes the container, function name, and optional args
ex. QUICK_STL(C,F,Args...)
2. Wrapper Function/Functor
- A class that takes the container, function name, and optional args
ex. quick_stl(F, C, Args...)
3. Overload Functions
- Overload every function in namespace std OR my library namespace
ex
namespace std { // or my library root namespace 'cherry'
template <typename C, typename T>
decltype(auto) count(const C& container, const T& value);
}
I usually steer clear of macros, but in this case it could certainty save alot
of lines of code from being written. With regards to function overloading, every single function that i want to use i must overload, which wouldn't really scale. The upside to that approach though is that you retain the names of the functions. With perfect forwarding and decltype(auto) overloading becomes alot easier, but still will take time to implement, and would have to be modified if ever another function was added. As to whether or not i should overload the std namespace i am rather skeptical on whether or not it would be appropriate in this case.
What would be the most appropriate way of going about overloading functions in the STD namespace (note these functions will only serve as proxy's to the original functions)?
You need to read this: Why do all functions take only ranges, not containers?
And This: STL algorithms: Why no additional interface for containers (additional to iterator pairs)?
I have been writing in c++ for a few months, and i am comfortable
enough with it now to begin implementing my own library...
Let me look on the brighter side and just say... Some of us have been there before.... :-)
One thing that nagged me was the fact that you always had to provide a
beginning and end iterator for functions like
std::accumulate,std::fill etc...
That's why you have Boost.Ranges and the Eric's proposed ranges that seems like it isn't gonna make it to C++17.
Macros
See Macros
Wrapper Function/Functor
Not too bad...Provided you do it correctly, You can do that, that's what essentially Ranges do for Containers... See the aforementioned implementations
Overload Functions
Overload every function in namespace std ...
Don't do that... The C++ standard doesn't like it.
See what the standard has to say
$17.6.4.2.1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within
namespace std unless otherwise specified. A program may add a template
specialization for any standard library template to namespace std only
if the declaration depends on a user-defined type and the
specialization meets the standard library requirements for the
original template and is not explicitly prohibited.

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.

How important is consistent usage of using declarations?

Most of the research I've done on the use of using declarations, including reading relevant sections of various style guides, indicates that whether or not to use using declarations in C++ source files, as long as they appear after all #includes, is a decision left to the coder. Even the style guides I read, which usually come down on one side or the other of such common disputes for the sake of consistency, are fairly flexible in this regard.
My question is, given this high degree of flexibility, how important is it to use a consistent style? For example, suppose an author wrote something like
using std::vector;
vector<T> v;
std::cout << v[0] << std::endl;
Is the inconsistent application of using on std::vector but not std::cout or std::endl generally considered acceptable, or would it be considered undisciplined?
I think the whole point of using is that you use it inconsistently among names. Names you need very frequently in some block can be declared locally with a using declaration, while others are not. I don't see a problem with that.
Declaring a name to have namespace scope is always much harder to take. I think if the name clearly is known to belong to a particular namespace so that confusing it with other namespaces won't occur, It won't hurt to put a using declaration if it makes your code more readable.
I am now a strong proponent for explicitly stating the namespace (ie no 'using')
Most peoples namespace history goes like this (in non trivial, >100kloc projects)
Innocence -> style 1
using namespace std;
Ouch -> style 2
using std::string;
using std::vector;
OK, enough already -> style 3
std::string foo = "xxx";
Assuming you don't say using namespace std; anywhere, I don't think most developers care one way or another in other people's code. The only thing that might bother them is the overuse of the std:: qualifier --- that is if you're saying "std::vector" 20 times in the function, maybe it's time for a "using std::vector". Otherwise, no one should care.
Sometimes, in my own code, I'll use the "std::" qualifier specifically to indicate that this is the only place that I'm using that identifer.
I try for not using using (no pun intended).
For saving typing, I like to do typedefs, e.g.:
typedef std::vector< int > IntVector;
typedef std::vector< Foo > FooVector;
This is less an answer than a counterpoint to a few other answers that have advocated always explicitly including the namespace as part of the name. At times, this is a poor idea. In some cases, you want to use a name that's been specialized for the type at hand if it exists, but use a standard-provided alternative otherwise.
As a typical example, let's consider a sort function. If you're sorting some objects of type T, you're going to end up swapping items. You want to use a special swap(T &, T&) if it exists, but template <class T> std::swap otherwise.
If you try to specify the full name of the swap you're going to use explicitly, you have to specify one or the other -- either you specify a specialized version, and instantiating your sort over a type that doesn't define it's own swap will fail, or else you specify std::swap, and ignore any swap that's been provided specifically for the type you're sorting.
using provides a way out of this dilemma though:
using namespace std;
template <class T>
mysort(/* ... */ ) {
// ...
if (less(x[a], x[b])
swap(x[a], x[b]);
// ...
}
Now, if the namespace in which T is found contains a swap(T &, T&), it'll be found via argument dependent lookup, and used above. If it doesn't exist, then std::swap will be found (and used) because the using namespace std; made it visible as well.
As an aside, I think with one minor modification, using namespace x; could be made almost entirely innocuous. As it stands right now, it introduces the names from that namespace into the current scope. If one of those happens to be the same as a name that exists in the current scope, we get a conflict. The problem, of course, is that we may not know everything that namespace contains, so there's almost always at least some potential for a conflict.
The modification would be to treat using namespace x; as if it created a scope surrounding the current scope, and introduced the names from that namespace into that surrounding scope. If one of those happened to be the same as a name introduced in the current scope, there would be no conflict though -- just like any other block scoping, the name in the current scope would hide the same name from the surrounding scope.
I haven't thought this through in a lot of detail, so there would undoubtedly be some corner cases that would require more care to solve, but I think the general idea would probably make a lot of things quite a bit simpler anyway.

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.