"See, I might expect the call to go to ::f(void * ), but because of the using declaration, the compiler will match it with N::f( char * )  not the function I wanted."

"Uh, well," I hemmed, "I guess that makes sense."

"Non-sense," the Guru snapped closed a thin, organge book [1]. "Prithee, child, what is the difference between the situation you have described, and this one," she took the marker from Wendy's hand and modified her code somewhat:

"The problem you have described is not the fault of the using directive, but rather the ambiguity caused by the overloaded function."

"So, you're saying it's okay to put in using directives?" I asked warily.

The Guru paused for a moment. "A few years back, there was a great dissension and discord in the Usenet group comp.lang.c++ .moderated. This normally meditative group was rocked with discussion on the pros and cons of the using directive [2]. Prophets great and small argued on both sides of the matter. No clear consensus emerged from that debate; indeed, the moderators shut down the discussion because it was generating more heat than light, as the proverb goes.

"My own opinion and recommendation is that namespaces are designed to resolve name clashes, not to prevent them. As such, our coding guidelines tell us to write using directives or declarations to taste, with some restrictions. Thou shalt not allow a using directive or using declaration to appear in a header, nor shalt thou suffer a using directive or using declaration to appear before any #include statements in a file."

"But..." Wendy started

"Peace, child," the Guru interrupted, holding up her hand. "The debate covered almost all possible arguments, and there was no compelling, overwhelming technical reason to go one way or the other. Our coding guidelines neither require nor prohibit using directives, other than in or before header files."

"Ah, one question," I ventured. "Actually, two. What's the difference between a using declaration and a using directive, and why can't they be in headers?"

"A using declaration nominates a specific member of a namespace to appear in the current scope. You are likely most familiar with them in derived classes, to correct name hiding." She wrote quickly on the whiteboard:

"Now, apprentice, you were wondering why using directives are not allowed in headers. You do not have any control over, and should not make any assumptions about, what headers are included before or after yours. Therefore, you have no idea what names you will be dragging into scope, which may affect users of your headers.

"Consider this parable, wherein a third-party header has a using directive in it:"

"You will now get a compiler error, when the compiler tries to parse the class UsesAmbiguous:

class UsesAmbiguous
{
Ambiguous a; // Error, which one?
};

"The using directive has added all names from the namespace ThirdParty into the global namespace. There is no way to cancel a using directive. However, this can be rectified, as using directives only apply to unqualified lookup. A fully qualified name will suppress names introduced by the using directive. "

class UsesAmbiguous
{
::Ambiguous a;
};

"The proper solution, of course, is to prevent such clashes in the first place, by avoiding using declarations in headers. Violating third-party headers, though, is dangerous."

"Oh, ick, I see," I said. "Well, couldn't we just limit the problem with a using declaration?"

"Sadly, no," the Guru said, clearing off the whiteboard. "Indeed, the problem could be even worse, for now your program can change its meaning depending on the order in which your headers are included. Using declarations only nominate names that are seen at the point of declaration, not names that are introduced later. Consider this parable,"

"This first parable lives a pious life, and behaves as expected. Since the using declaration appears at the end of header B, the declaration nominates both versions of f for consideration in unqualified name lookup.

"Consider, however, the effect of changing the order of include statements:"

"When the compiler encounters the using declaration in header B, it only adds names from the namespace ABigProject that it has already seen. In this case, it has only seen f( double ). When the compiler encounters the unqualified call in main(), it does not consider looking at f(int), for that function still resides only in its namespace, not in the global namespace.

"If you are lucky, the ambiguity will be one that the compiler cannot resolve, and you will get a compile error. If you aren't lucky, well..." I shuddered at the thought of what might lie down that road.

"Okay, so I see why we can't use them in headers," I said at long last. "But what's wrong with putting them before #include statements?"

"I bet I know." I jumped a little at Kerry's voice. I hadn't noticed him joining the conversation. "Suppose header B behaved correctly," he said, erasing the using declaration from the whiteboard. "If you put a using declaration right after header B, it would be exactly the same as if the declaration was in the header, with the same results:

"Very good, young apprentice," the Guru approved. I felt a little chagrined at not having seen that for myself.

"One thing I don't get, though," Kerry said. "Is it okay to put a using directive or declaration in a namespace scope, like this?"

// some header
namespace N
{
using namespace std;
int count;
}

"After all, now you've limited the scope of the using directive, so you should be okay, right?"

"A good question, young apprentice, which deserves a good answer. Apprentice?" I realized she meant me. I kicked in the thought-afterburners.

"Well, it's obvious," I said, stalling for time. Then I remembered something the Guru had mentioned earlier. "You...uh...don't have any control over what other headers are going to be used. That's it! Yes, and if the source file is using another header with a conflicting name, you'll have problems. Here," I grabbed the marker and started writing:

"Here, I meant to refer to N::count. But, namespace N pulls the entire std namespace into its scope. So, when I say count, the compiler doesn't know if I meant N::count or std::count from <algorithm>. Since there's no way to turn off the using declaration, I now have to qualify each mention of count  something I wouldn't have had to do, if the using directive wasn't in the header."

"Very good, apprentice. So, to sum up: Apply using directives or using declarations to taste  or not at all, if you prefer. Never put using declarations or directives in a header, not even at a namespace scope. One last point that must be mentioned. The most pious among us will put each project in its own namespace. This allows us at a later time to easily disambiguate any name clashes that may arise."

Herb Sutter (http://www.gotw.ca/) is convener of the ISO C++ Standards committee, author of Exceptional C++ and More Exceptional C++, and Visual C++ architect for Microsoft.
Jim Hyslop is a senior software designer for Leitch Technology International. He can be reached at jhyslop@ieee.orgM/a>.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!