防止C ++中名称空间中毒的绝佳方法 [英] Elegant way to prevent namespace poisoning in C++

查看:56
本文介绍了防止C ++中名称空间中毒的绝佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设 Bob 将其库包装到名称空间"bob"中,,而 Alice 将使整个名称空间在内部可见单个使用命名空间bob" 而不是对每个项目使用使用bob :: XYZ" 来实现自己的功能:

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:

// 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;
}

另一方面,鲍勃(Bob)试图通过将实现包装在虚拟命名空间中并在仅这些符号可用()中使用来防止此类情况,这些符号供其他用户使用:

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:

// 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;

}

由于所有using指令都被包装到Bobs主命名空间中的虚拟"impl_"命名空间中,因此Alice也没有从std ::命名空间意外导入符号的风险..

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.

所以,我的问题是:

  1. 我不喜欢有一个用于实现细节的虚拟名称空间,从理论上讲,每个人都可以看到该名称空间.能够使用e中的许多符号的正确方法是什么? G. std ::不会泄漏这些AND,并且不会在每个显式符号前加上std ::?前缀. (我也在考虑生成的API文档,该文档显示"bob :: impl _ :: XYZ"而不是"bob :: XYZ".)
  2. 我认为,重复std ::不是很干燥. s. o.一次又一次到处.我还了解到,在较大范围内(例如一个类),一个相对全局的使用名称空间std"并不是那么漂亮,但我认为数百个std ::前缀要丑陋得多.哪种方法更好?

推荐答案

让我们假设 Alice 使用的两个库分别是 Bob Charlie .

Let's suppose that Alice is using two libraries, made by Bob and 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
}

现在,查理(Charlie)发明了一项名为foobar的新功能,并将其添加到自己的库中. foobar很棒,他的用户喜欢它.爱丽丝也开始使用它.

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我可以在我的库中使用.但是我不想依赖于Charlie."因此,他创建了自己的版本.

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.

哦,哦,现在爱丽丝的代码无法编译!爱丽丝代码中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.

然后,下个月也会发生同样的事情.然后是下个月.

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

现在,所有Alice的客户都非常不满意,因为他们正在开发大型技术并试图保持其依赖项的最新版本,但是每当他们尝试进行任何升级时,Alice的代码都会被淘汰.他们在她的错误跟踪器上报告了很多错误.

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 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和Charlie将电子邮件发送回Alice:

Bob and Charlie send an email back to Alice:

没有爱丽丝,您需要停止在代码中放置using namespace bob;using namespace charlie;. Bob或Charlie都不支持.

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.


现在,让我们再讲一个故事,除了没有查理.只是爱丽丝在自己的项目中制作自己的课程,与鲍勃添加的新名称发生冲突.


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.

简而言之,在我看来,using namespace指令绝不是一个好主意. 特别是(当名称空间是外部库时).您真的不知道将来该命名空间将如何更改,如果它以对您完全不利的方式更改,您的手上会突然变得一团糟.

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.

使用namespace =缩短命名空间通常是一个很好的主意.我喜欢执行以下操作:

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

这样,我就可以在my_lib中使用简称qi,但是我并没有在用户身上强加任何内容. (我希望谁会using 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;!)

如果您是用户,则可以执行类似的操作

If you are a user, you could do something like

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

但是,无论您是用户还是库实现者,您都应该乐于输入像bob::std::这样的短名称空间,如果这意味着在升级库时代码不会中断

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.

这与DRY无关.在名称上加上某种 限定符可以使您更轻松地阅读代码并理解其含义.

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.

例如,查看流行的C库SDL.据我所知,SDL中的每个宏均以SDL_开头,而每个函数均以sdl_开头.这是否违反"DRY"?否.此处没有重复的实现细节-通用前缀用于避免名称冲突.而且,它使代码更具可读性和可维护性-每当我看到一个正在谈论SDL实体的符号时,我便立即知道.这对人类和计算机都非常有帮助.

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.

放置using namespace std;using namespace my_lib;就像获取C ++最佳功能之一并将其扔到垃圾中一样.折衷方案是,省去了输入5个字符的代价,这是以损害可读性和可维护性为代价的.

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.

分手思考:using namespace如何影响收到的错误消息的质量.

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;
}

当编译器看到此代码时,将不得不尝试了解的每个流运算符重载,并检查foo是否可转换为任何这些东西.因为std::cout是参数之一,所以ADL意味着我们必须搜索整个std命名空间.事实证明,foo不能转换为任何这些东西.在gcc 5.3上,我收到以下(200行)错误消息.

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.

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;
                    ^

重点是:如果您执行using namespace bob;,那么bob的每个可流式类型也将出现在该列表中!如果您执行using namespace charlie;,那么他的所有类型也都在那里!

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的类型偶尔可以流式转换为Charlie的类型之一怎么办?而且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?

当然,这不仅适用于任何运算符重载,而且适用于任何模板或函数调用.

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

因此,最重要的是,如果您避免在一个命名空间中将大量废话混在一起,C ++的推理就容易得多,并且效果也更好.

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 ++中名称空间中毒的绝佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆