SF.10: Avoid dependencies on implicitly `#included` names
This commit is contained in:
Bjarne Stroustrup 2017-05-17 15:06:48 -04:00
parent 974fdf4661
commit 50576c0144

View File

@ -17077,6 +17077,7 @@ Source file rule summary:
* [SF.7: Don't write `using namespace` in a header file](#Rs-using-directive)
* [SF.8: Use `#include` guards for all `.h` files](#Rs-guards)
* [SF.9: Avoid cyclic dependencies among source files](#Rs-cycles)
* [SF.10: Avoid dependencies on implicitly `#included` names](#Rs-implicit)
* [SF.20: Use `namespace`s to express logical structure](#Rs-namespace)
* [SF.21: Don't use an unnamed (anonymous) namespace in a header](#Rs-unnamed)
@ -17411,6 +17412,76 @@ Eliminate cycles; don't just break them with `#include` guards.
Flag all cycles.
### <a name="Rs-implicit"></a>SF.10: Avoid dependencies on implicitly `#included` names
##### Reason
Avoid surprises.
Avoid having to change `#include`s if an `#include`d header changes.
Avoid accidentally becoming dependent on implementation details and logically separate entities included in a header.
##### Example
#include<iostream>
using namespace std;
void use() // bad
{
string s;
cin >> s; // fine
getline(cin,s); // error: getline() not defined
if (s=="surprise") { // error == not defined
// ...
}
}
<iostream> exposes the definition of `std::string` ("why?" makes for a fun trivia question),
but it is not required to do so by transitively including the entire `<string>` header,
resulting in the popular beginner question "why doesn't `getline(cin,s);` work?"
or even an occasional "`string`s cannot be compared with `==`).
The solution is to explicitly `#include<string>`:
#include<iostream>
#include<string>
using namespace std;
void use()
{
string s;
cin >> s; // fine
getline(cin,s); // fine
if (s=="surprise") { // fine
// ...
}
}
##### Note
Some headers exist exactly to collect a set of consistent declarations from a variety of headers.
For example:
// basic_std_lib.h:
#include<vector>
#include<string>
#include<map>
#include<iostream>
#include<random>
#include<vector>
a user can now get that set of declarations with a single `#include`"
#include "basic_std_lib.h"
This rule against implicit inclusion is not meant to prevent such deliberate aggregation.
##### Enforcement
Enforcement would require some knowledge about what in a header is meant to be "exported" to users and what is there to enable implementation.
No really good solution is possible until we have modules.
### <a name="Rs-namespace"></a>SF.20: Use `namespace`s to express logical structure
##### Reason