在c++中防止名称空间中毒的优雅方法。

时间:2022-10-16 20:23:27

Let's assume, Bob has wrapped his library into the namespace "bob", and Alice is going to make the whole namespace visible inside her own function by a single "using namespace bob", instead of "using bob::XYZ" for every single item:

假设Bob已经将他的库包装为“Bob”的名称空间,而Alice将通过一个“使用名称空间Bob”来将整个名称空间显示在她自己的函数中,而不是“使用Bob::XYZ”用于每一个项目:

// This file is written by Alice:
#include <iostream>

// She uses Bobs library:
#include "bob.hpp"

int main(void) {
    // Import Bobs library and use it:
    using namespace bob;

    unsigned short value = 50000;
    bob::dump_as_signed(value);

    // Should not be possible without std:: prefix:
    cout << "foobar" << endl;
}

On the other hand, Bob tried to prevent such scenarios by wrapping the implementation inside a dummy namespace, and making only these symbols available, which are intended for other users:

另一方面,Bob试图通过将实现封装到一个虚拟的名称空间中来防止这种情况的发生,并且只提供这些可用的符号,这些符号是为其他用户准备的:

// This file is written by Bob
#include <iostream>
#include <type_traits>

// Namespace for public use:
namespace bob {

    // Implementation details:
    namespace impl_ {

        // Visible ONLY within sub-namespace:
        using std::cout;
        using std::endl;

        using std::is_integral;
        using std::make_signed;

        // No repeated std:: prefixes at all:
        template <typename T,
            typename S = typename make_signed<T>::type>
        void dump_as_signed(const T i) {
            static_assert(is_integral<T>::value, "no integer");

            // Do something very very useful:
            cout << "signed:" << static_cast<S>(i) << endl;
        }
    }

    // Make available without poisoning with std::*:
    using impl_::dump_as_signed;

}

Because of all using directives are wrapped into a dummy "impl_" namespace within Bobs major namespace, there is no risk for Alice to accidently import symbols from the std:: namespace, too.

由于所有的使用指令都被封装在Bobs主名称空间内的一个虚拟“request_”名称空间中,因此Alice不可能不小心从std中导入符号::名称空间。

So, my questions are:

  1. I don't like that there is a dummy namespace for implementation details, which is "theoretically" visible for everybody. Is there a nicer way, to be able to use many symbols from for e. g. std:: without leaking these AND without prefixing every symbol explicit with std::? (I'm also thinking about generated API-Docs, which show "bob::impl_::XYZ" instead of "bob::XYZ".)
  2. 我不喜欢在实现细节上有一个虚拟的名称空间,这在理论上是每个人都可以看到的。是否有更好的方法,可以使用许多符号,例如,std::不泄露这些,并且不预先确定每个符号明确的std::?(我也在考虑生成的api文档,它显示“bob::XYZ”而不是“bob: XYZ”。)
  3. I think, it is not very DRY to repeat std:: a. s. o. again and again everywhere. I also understand that a relatively global "using namespace std" inside a larger scope (such as a class) isn't that beautiful, but hundreds of std:: prefixes are much uglier, in my opinion. Aside from poisoning problems: Which do you think is nicer, and WHY? Or got a completely different idea?
  4. 我想,重复std不是很干燥:a. s. o.一次又一次到处都是。我还知道,一个相对全局的“使用名称空间std”在更大的范围内(比如一个类)并不那么漂亮,但是有数百个std::在我看来,前缀更丑。除了中毒问题:你认为哪个更好,为什么?或者有完全不同的想法?

OK, I hope my question is clear. Thanks for reading! :)

好的,我希望我的问题是清楚的。感谢你的阅读!:)

1 个解决方案

#1


5  

Let's suppose that Alice is using two libraries, made by Bob and Charlie.

假设Alice使用了由Bob和Charlie创建的两个库。

// This file is written by Alice:
#include <bob.hpp>
#include <charlie.hpp>

int main(void) {
  using namespace bob;
  using namespace charlie;

  // Do a bunch of stuff
}

Now, Charlie invents a new feature called foobar which he adds to his library. foobar is great and his users like it. Alice starts using it also.

现在,查理发明了一种叫做foobar的新功能,他把它添加到他的图书馆里。foobar是伟大的,他的用户喜欢它。爱丽丝也开始使用它。

Then Bob says, "I like foobar also, I want to have my own foobar I can use in my library. But I don't want a dependency on Charlie." So he creates his own version.

然后Bob说,“我也喜欢foobar,我想要我自己的foobar,我可以在我的图书馆里使用。”但我不想依赖查理。”所以他创造了自己的版本。

Uh oh, now Alice's code doesn't compile! Every usage of foobar in Alice's code is ambiguous and she has to rewrite her whole project.

哦,现在Alice的代码不能编译!在Alice的代码中,foobar的每一个用法都是模糊的,她必须重写整个项目。

Then, the same thing happens next month. And the next month after that.

然后,同样的事情在下个月发生。然后下个月。

Now, all of Alice's customers are really unhappy because they are building large technologies and trying to keep up-to-date versions of their dependencies, but every time they try to upgrade anything, Alice's code craps out. They make a lot of bug reports on her bug tracker.

现在,Alice的所有客户都非常不高兴,因为他们正在构建大型的技术,并试图保持其依赖的最新版本,但是每次他们试图升级任何东西时,Alice的代码就会崩溃。他们在她的bug追踪器上做了很多bug报告。

Alice sends an email to Bob and Charlie and says

爱丽丝给鲍勃和查理发了一封电子邮件,说。

Guys, you have to stop making classes with the same names, or I'm going to lose all of my business!

伙计们,你们必须停止用相同的名字来上课,否则我将失去我所有的生意!

Bob and Charlie send an email back to Alice:

Bob和Charlie向Alice发送邮件:

No Alice, you need to stop putting using namespace bob; and using namespace charlie; in your code. That is not supported by Bob or by Charlie.

没有Alice,你需要停止使用名称空间bob;查理和使用名称空间;在您的代码中。这不是Bob或Charlie支持的。


Now, let's tell the same story again, except there is no Charlie. It's just Alice making her own classes in her project, colliding with new names added by Bob.

现在,让我们再讲一遍同样的故事,除了没有查理。这只是Alice在自己的项目中创建自己的类,与Bob添加的新名称发生冲突。


In short, a using namespace directive is never a good idea (in my opinion). Especially when the namespace is an external library. You don't really know how that namespace can change in the future, and if it changes in a way that is at all bad for you, you suddenly have a huge mess on your hands.

简而言之,使用名称空间指令从来都不是一个好主意(在我看来)。特别是当名称空间是一个外部库时。你真的不知道这个名称空间在将来会如何改变,如果它改变的方式对你来说很糟糕,你的手就会突然变得一团糟。

Using namespace = to shorten namespaces is often a very good idea. I like to do the following:

使用名称空间=缩短名称空间通常是一个非常好的主意。我喜欢这样做:

namespace my_lib {

namespace qi = boost::spirit::qi;

// Do stuff with qi
// ...

} // end namespace my_lib

That way I get to use the short name qi in my_lib, but I don't impose anything on my users. (Who I expect will not be doing using namespace my_lib;!)

这样我就可以在my_lib中使用短名称qi,但是我不会对我的用户强加任何东西。(我希望不会使用命名空间my_lib;!)

If you are a user, you could do something like

如果你是一个用户,你可以做一些类似的事情。

namespace cha = charlie::name::space::is_way_too_long;

But, you should be more than happy to type short namespaces like bob:: or std::, whether you are a user or a library implementor, if it will mean that your code doesn't break when the libraries are upgraded.

但是,您应该非常乐意键入诸如bob::或std::,无论您是用户还是库实实者的名称空间,如果这意味着您的代码在更新库时不会中断。

This is not about DRY. Putting some kind of qualifier on names makes it much easier to read your code and understand what it means.

这不是关于干的。在名称上添加一些限定符会使您更容易阅读代码并理解它的含义。

For instance look at SDL, a popular C library. To my knowledge, every macro in SDL begins SDL_ and every function begins sdl_. Is that a violation of "DRY"? No. There are no duplicated implementation details here -- the common prefix is there to avoid name collisions. Also, it makes the code more readable and maintainable -- whenever I see a symbol that is talking about an SDL entity I know so immediately. It's very helpful to both the humans and the computers.

例如,查看一个流行的C库SDL。据我所知,SDL的每个宏都开始SDL_,每个函数都开始SDL_。这是对“干”的侵犯吗?不。这里没有重复的实现细节——公共前缀是为了避免名称冲突。而且,它使代码更易于阅读和维护——每当我看到一个符号,它就是我所知道的SDL实体。它对人类和电脑都很有帮助。

Putting using namespace std; or using namespace my_lib; is like taking one of C++ best features and throwing it in the garbage. The trade-off is, save yourself typing 5 characters, at the cost of making a great harm to readability and maintainability.

将使用名称空间性病;或者使用名称空间my_lib;就像使用c++最好的特性,并将其扔进垃圾中。这样做的代价是,节省输入5个字符,代价是对可读性和可维护性造成极大的损害。


Parting thought: How does using namespace affect the quality of the error messages that you get.

分离思想:使用名称空间如何影响您得到的错误消息的质量。

Here's a simple program that doesn't compile:

下面是一个不编译的简单程序:

#include <iostream>

struct foo {};

int main() {
  std::cout << foo{} << std::endl;
}

When the compiler sees this code, it is going to have to try every stream operator overload that it knows about and check if foo is convertible to any of those things. Because std::cout is one of the arguments, ADL means that we have to search the entire std namespace. Turns out, surprise surprise, foo isn't convertible to any of those things. On gcc 5.3 I get the following (200 line) error message.

当编译器看到这段代码时,它将不得不尝试每一个流操作符重载,它知道并检查foo是否可转换为任何这些东西。因为std::cout是其中一个参数,ADL意味着我们必须搜索整个std名称空间。结果是,奇怪的是,foo不能转换成任何东西。在gcc 5.3中,我得到了以下(200行)错误消息。

main.cpp: In function ‘int main()’:
main.cpp:6:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘foo’)
   std::cout << foo{} << std::endl;
             ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo] <near match>
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
/usr/include/c++/5/ostream:628:5: note:   conversion of argument 1 would be ill-formed:
main.cpp:6:20: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(__ostream_type& (*__pf)(__ostream_type&))
       ^
/usr/include/c++/5/ostream:108:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’
/usr/include/c++/5/ostream:117:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
       operator<<(__ios_type& (*__pf)(__ios_type&))
       ^
/usr/include/c++/5/ostream:117:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/5/ostream:127:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(ios_base& (*__pf) (ios_base&))
       ^
/usr/include/c++/5/ostream:127:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/5/ostream:166:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long __n)
       ^
/usr/include/c++/5/ostream:166:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long int’
/usr/include/c++/5/ostream:170:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long __n)
       ^
/usr/include/c++/5/ostream:170:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long unsigned int’
/usr/include/c++/5/ostream:174:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(bool __n)
       ^
/usr/include/c++/5/ostream:174:7: note:   no known conversion for argument 1 from ‘foo’ to ‘bool’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:91:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:91:5: note:   no known conversion for argument 1 from ‘foo’ to ‘short int’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:181:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned short __n)
       ^
/usr/include/c++/5/ostream:181:7: note:   no known conversion for argument 1 from ‘foo’ to ‘short unsigned int’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:105:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:105:5: note:   no known conversion for argument 1 from ‘foo’ to ‘int’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:192:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned int __n)
       ^
/usr/include/c++/5/ostream:192:7: note:   no known conversion for argument 1 from ‘foo’ to ‘unsigned int’
/usr/include/c++/5/ostream:201:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long long __n)
       ^
/usr/include/c++/5/ostream:201:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long long int’
/usr/include/c++/5/ostream:205:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long long __n)
       ^
/usr/include/c++/5/ostream:205:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long long unsigned int’
/usr/include/c++/5/ostream:220:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(double __f)
       ^
/usr/include/c++/5/ostream:220:7: note:   no known conversion for argument 1 from ‘foo’ to ‘double’
/usr/include/c++/5/ostream:224:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(float __f)
       ^
/usr/include/c++/5/ostream:224:7: note:   no known conversion for argument 1 from ‘foo’ to ‘float’
/usr/include/c++/5/ostream:232:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long double __f)
       ^
/usr/include/c++/5/ostream:232:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long double’
/usr/include/c++/5/ostream:245:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(const void* __p)
       ^
/usr/include/c++/5/ostream:245:7: note:   no known conversion for argument 1 from ‘foo’ to ‘const void*’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:119:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:119:5: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:574:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)
     operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
     ^
/usr/include/c++/5/ostream:574:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const unsigned char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:569:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)
     operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
     ^
/usr/include/c++/5/ostream:569:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const signed char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:556:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)
     operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
     ^
/usr/include/c++/5/ostream:556:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:321:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)
     operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
     ^
/usr/include/c++/5/bits/ostream.tcc:321:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:539:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*)
     operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
     ^
/usr/include/c++/5/ostream:539:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   mismatched types ‘const _CharT*’ and ‘foo’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:519:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char)
     operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
     ^
/usr/include/c++/5/ostream:519:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘unsigned char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:514:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char)
     operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
     ^
/usr/include/c++/5/ostream:514:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘signed char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:508:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char)
     operator<<(basic_ostream<char, _Traits>& __out, char __c)
     ^
/usr/include/c++/5/ostream:508:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:502:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char)
     operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
     ^
/usr/include/c++/5/ostream:502:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:497:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT)
     operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
     ^
/usr/include/c++/5/ostream:497:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘foo’)
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/bits/ios_base.h:46:0,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/system_error:209:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&)
     operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
     ^
/usr/include/c++/5/system_error:209:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const std::error_code&’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:5172:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
     operator<<(basic_ostream<_CharT, _Traits>& __os,
     ^
/usr/include/c++/5/bits/basic_string.h:5172:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   ‘foo’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’
   std::cout << foo{} << std::endl;
                    ^

Here's the point: If you do using namespace bob;, then every one of bob's types that is streamable is also going to appear in that list! If you do using namespace charlie; then all of his types will be there too!

关键是:如果您使用名称空间bob;那么,可流的bob的每一个类型都将出现在该列表中!如果使用命名空间charlie;然后他的所有类型也会在那里!

Not only will the error messages be worse, there's a greater chance that you can get some really bizarre interaction that you didn't expect. What if Bob's types are occasionally streamable into one of Charlie's types? And Charlie's types are occasionally implicitly convertible to some standard type that is streamable?

错误信息不仅会变得更糟,还会有更大的机会让你得到意想不到的奇怪的互动。如果Bob的类型偶尔会变成Charlie的类型呢?查理的类型偶尔也会被隐式转换为一些可流式的标准类型?

And of course this all applies not just to any operator overload, but any template or function call.

当然,这不仅仅适用于任何操作符重载,也适用于任何模板或函数调用。

So, bottom line, C++ is a lot easier to reason about and works a lot better if you avoid mixing lots of crap together in one namespace.

因此,如果你避免在一个名称空间中混合大量的垃圾,那么,c++更容易推理和工作得更好。

#1


5  

Let's suppose that Alice is using two libraries, made by Bob and Charlie.

假设Alice使用了由Bob和Charlie创建的两个库。

// This file is written by Alice:
#include <bob.hpp>
#include <charlie.hpp>

int main(void) {
  using namespace bob;
  using namespace charlie;

  // Do a bunch of stuff
}

Now, Charlie invents a new feature called foobar which he adds to his library. foobar is great and his users like it. Alice starts using it also.

现在,查理发明了一种叫做foobar的新功能,他把它添加到他的图书馆里。foobar是伟大的,他的用户喜欢它。爱丽丝也开始使用它。

Then Bob says, "I like foobar also, I want to have my own foobar I can use in my library. But I don't want a dependency on Charlie." So he creates his own version.

然后Bob说,“我也喜欢foobar,我想要我自己的foobar,我可以在我的图书馆里使用。”但我不想依赖查理。”所以他创造了自己的版本。

Uh oh, now Alice's code doesn't compile! Every usage of foobar in Alice's code is ambiguous and she has to rewrite her whole project.

哦,现在Alice的代码不能编译!在Alice的代码中,foobar的每一个用法都是模糊的,她必须重写整个项目。

Then, the same thing happens next month. And the next month after that.

然后,同样的事情在下个月发生。然后下个月。

Now, all of Alice's customers are really unhappy because they are building large technologies and trying to keep up-to-date versions of their dependencies, but every time they try to upgrade anything, Alice's code craps out. They make a lot of bug reports on her bug tracker.

现在,Alice的所有客户都非常不高兴,因为他们正在构建大型的技术,并试图保持其依赖的最新版本,但是每次他们试图升级任何东西时,Alice的代码就会崩溃。他们在她的bug追踪器上做了很多bug报告。

Alice sends an email to Bob and Charlie and says

爱丽丝给鲍勃和查理发了一封电子邮件,说。

Guys, you have to stop making classes with the same names, or I'm going to lose all of my business!

伙计们,你们必须停止用相同的名字来上课,否则我将失去我所有的生意!

Bob and Charlie send an email back to Alice:

Bob和Charlie向Alice发送邮件:

No Alice, you need to stop putting using namespace bob; and using namespace charlie; in your code. That is not supported by Bob or by Charlie.

没有Alice,你需要停止使用名称空间bob;查理和使用名称空间;在您的代码中。这不是Bob或Charlie支持的。


Now, let's tell the same story again, except there is no Charlie. It's just Alice making her own classes in her project, colliding with new names added by Bob.

现在,让我们再讲一遍同样的故事,除了没有查理。这只是Alice在自己的项目中创建自己的类,与Bob添加的新名称发生冲突。


In short, a using namespace directive is never a good idea (in my opinion). Especially when the namespace is an external library. You don't really know how that namespace can change in the future, and if it changes in a way that is at all bad for you, you suddenly have a huge mess on your hands.

简而言之,使用名称空间指令从来都不是一个好主意(在我看来)。特别是当名称空间是一个外部库时。你真的不知道这个名称空间在将来会如何改变,如果它改变的方式对你来说很糟糕,你的手就会突然变得一团糟。

Using namespace = to shorten namespaces is often a very good idea. I like to do the following:

使用名称空间=缩短名称空间通常是一个非常好的主意。我喜欢这样做:

namespace my_lib {

namespace qi = boost::spirit::qi;

// Do stuff with qi
// ...

} // end namespace my_lib

That way I get to use the short name qi in my_lib, but I don't impose anything on my users. (Who I expect will not be doing using namespace my_lib;!)

这样我就可以在my_lib中使用短名称qi,但是我不会对我的用户强加任何东西。(我希望不会使用命名空间my_lib;!)

If you are a user, you could do something like

如果你是一个用户,你可以做一些类似的事情。

namespace cha = charlie::name::space::is_way_too_long;

But, you should be more than happy to type short namespaces like bob:: or std::, whether you are a user or a library implementor, if it will mean that your code doesn't break when the libraries are upgraded.

但是,您应该非常乐意键入诸如bob::或std::,无论您是用户还是库实实者的名称空间,如果这意味着您的代码在更新库时不会中断。

This is not about DRY. Putting some kind of qualifier on names makes it much easier to read your code and understand what it means.

这不是关于干的。在名称上添加一些限定符会使您更容易阅读代码并理解它的含义。

For instance look at SDL, a popular C library. To my knowledge, every macro in SDL begins SDL_ and every function begins sdl_. Is that a violation of "DRY"? No. There are no duplicated implementation details here -- the common prefix is there to avoid name collisions. Also, it makes the code more readable and maintainable -- whenever I see a symbol that is talking about an SDL entity I know so immediately. It's very helpful to both the humans and the computers.

例如,查看一个流行的C库SDL。据我所知,SDL的每个宏都开始SDL_,每个函数都开始SDL_。这是对“干”的侵犯吗?不。这里没有重复的实现细节——公共前缀是为了避免名称冲突。而且,它使代码更易于阅读和维护——每当我看到一个符号,它就是我所知道的SDL实体。它对人类和电脑都很有帮助。

Putting using namespace std; or using namespace my_lib; is like taking one of C++ best features and throwing it in the garbage. The trade-off is, save yourself typing 5 characters, at the cost of making a great harm to readability and maintainability.

将使用名称空间性病;或者使用名称空间my_lib;就像使用c++最好的特性,并将其扔进垃圾中。这样做的代价是,节省输入5个字符,代价是对可读性和可维护性造成极大的损害。


Parting thought: How does using namespace affect the quality of the error messages that you get.

分离思想:使用名称空间如何影响您得到的错误消息的质量。

Here's a simple program that doesn't compile:

下面是一个不编译的简单程序:

#include <iostream>

struct foo {};

int main() {
  std::cout << foo{} << std::endl;
}

When the compiler sees this code, it is going to have to try every stream operator overload that it knows about and check if foo is convertible to any of those things. Because std::cout is one of the arguments, ADL means that we have to search the entire std namespace. Turns out, surprise surprise, foo isn't convertible to any of those things. On gcc 5.3 I get the following (200 line) error message.

当编译器看到这段代码时,它将不得不尝试每一个流操作符重载,它知道并检查foo是否可转换为任何这些东西。因为std::cout是其中一个参数,ADL意味着我们必须搜索整个std名称空间。结果是,奇怪的是,foo不能转换成任何东西。在gcc 5.3中,我得到了以下(200行)错误消息。

main.cpp: In function ‘int main()’:
main.cpp:6:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘foo’)
   std::cout << foo{} << std::endl;
             ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo] <near match>
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
/usr/include/c++/5/ostream:628:5: note:   conversion of argument 1 would be ill-formed:
main.cpp:6:20: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(__ostream_type& (*__pf)(__ostream_type&))
       ^
/usr/include/c++/5/ostream:108:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’
/usr/include/c++/5/ostream:117:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
       operator<<(__ios_type& (*__pf)(__ios_type&))
       ^
/usr/include/c++/5/ostream:117:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/5/ostream:127:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(ios_base& (*__pf) (ios_base&))
       ^
/usr/include/c++/5/ostream:127:7: note:   no known conversion for argument 1 from ‘foo’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/5/ostream:166:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long __n)
       ^
/usr/include/c++/5/ostream:166:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long int’
/usr/include/c++/5/ostream:170:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long __n)
       ^
/usr/include/c++/5/ostream:170:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long unsigned int’
/usr/include/c++/5/ostream:174:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(bool __n)
       ^
/usr/include/c++/5/ostream:174:7: note:   no known conversion for argument 1 from ‘foo’ to ‘bool’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:91:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:91:5: note:   no known conversion for argument 1 from ‘foo’ to ‘short int’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:181:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned short __n)
       ^
/usr/include/c++/5/ostream:181:7: note:   no known conversion for argument 1 from ‘foo’ to ‘short unsigned int’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:105:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:105:5: note:   no known conversion for argument 1 from ‘foo’ to ‘int’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:192:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned int __n)
       ^
/usr/include/c++/5/ostream:192:7: note:   no known conversion for argument 1 from ‘foo’ to ‘unsigned int’
/usr/include/c++/5/ostream:201:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long long __n)
       ^
/usr/include/c++/5/ostream:201:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long long int’
/usr/include/c++/5/ostream:205:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(unsigned long long __n)
       ^
/usr/include/c++/5/ostream:205:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long long unsigned int’
/usr/include/c++/5/ostream:220:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(double __f)
       ^
/usr/include/c++/5/ostream:220:7: note:   no known conversion for argument 1 from ‘foo’ to ‘double’
/usr/include/c++/5/ostream:224:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(float __f)
       ^
/usr/include/c++/5/ostream:224:7: note:   no known conversion for argument 1 from ‘foo’ to ‘float’
/usr/include/c++/5/ostream:232:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(long double __f)
       ^
/usr/include/c++/5/ostream:232:7: note:   no known conversion for argument 1 from ‘foo’ to ‘long double’
/usr/include/c++/5/ostream:245:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(const void* __p)
       ^
/usr/include/c++/5/ostream:245:7: note:   no known conversion for argument 1 from ‘foo’ to ‘const void*’
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:119:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
     basic_ostream<_CharT, _Traits>::
     ^
/usr/include/c++/5/bits/ostream.tcc:119:5: note:   no known conversion for argument 1 from ‘foo’ to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:574:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)
     operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
     ^
/usr/include/c++/5/ostream:574:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const unsigned char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:569:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)
     operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
     ^
/usr/include/c++/5/ostream:569:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const signed char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:556:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)
     operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
     ^
/usr/include/c++/5/ostream:556:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/ostream.tcc:321:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)
     operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
     ^
/usr/include/c++/5/bits/ostream.tcc:321:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const char*’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:539:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*)
     operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
     ^
/usr/include/c++/5/ostream:539:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   mismatched types ‘const _CharT*’ and ‘foo’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:519:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char)
     operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
     ^
/usr/include/c++/5/ostream:519:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘unsigned char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:514:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char)
     operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
     ^
/usr/include/c++/5/ostream:514:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘signed char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:508:5: note: candidate: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char)
     operator<<(basic_ostream<char, _Traits>& __out, char __c)
     ^
/usr/include/c++/5/ostream:508:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:502:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char)
     operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
     ^
/usr/include/c++/5/ostream:502:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘char’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                 from main.cpp:1:
/usr/include/c++/5/ostream:497:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT)
     operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
     ^
/usr/include/c++/5/ostream:497:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘foo’)
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/bits/ios_base.h:46:0,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/system_error:209:5: note: candidate: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&)
     operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
     ^
/usr/include/c++/5/system_error:209:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   cannot convert ‘foo{}’ (type ‘foo’) to type ‘const std::error_code&’
   std::cout << foo{} << std::endl;
                    ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:5172:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
     operator<<(basic_ostream<_CharT, _Traits>& __os,
     ^
/usr/include/c++/5/bits/basic_string.h:5172:5: note:   template argument deduction/substitution failed:
main.cpp:6:20: note:   ‘foo’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’
   std::cout << foo{} << std::endl;
                    ^

Here's the point: If you do using namespace bob;, then every one of bob's types that is streamable is also going to appear in that list! If you do using namespace charlie; then all of his types will be there too!

关键是:如果您使用名称空间bob;那么,可流的bob的每一个类型都将出现在该列表中!如果使用命名空间charlie;然后他的所有类型也会在那里!

Not only will the error messages be worse, there's a greater chance that you can get some really bizarre interaction that you didn't expect. What if Bob's types are occasionally streamable into one of Charlie's types? And Charlie's types are occasionally implicitly convertible to some standard type that is streamable?

错误信息不仅会变得更糟,还会有更大的机会让你得到意想不到的奇怪的互动。如果Bob的类型偶尔会变成Charlie的类型呢?查理的类型偶尔也会被隐式转换为一些可流式的标准类型?

And of course this all applies not just to any operator overload, but any template or function call.

当然,这不仅仅适用于任何操作符重载,也适用于任何模板或函数调用。

So, bottom line, C++ is a lot easier to reason about and works a lot better if you avoid mixing lots of crap together in one namespace.

因此,如果你避免在一个名称空间中混合大量的垃圾,那么,c++更容易推理和工作得更好。