优雅的方法来防止C ++中的命名空间中毒

问题描述 投票:2回答:1

让我们假设,Bob将他的库包装到命名空间“bob”中,并且Alice将通过单个“using namespace 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;
}

另一方面,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;

}

由于所有using指令都被包装到Bobs主命名空间内的虚拟“impl_”命名空间中,因此Alice也不会意外地从std :: namespace导入符号。

所以,我的问题是:

  1. 我不喜欢有一个虚拟命名空间用于实现细节,这对于每个人来说都是“理论上”可见的。什么是能够使用e的许多符号的正确方法。 G。 std ::没有泄漏这些AND而没有用std ::前缀每个符号显式? (我也在考虑生成API-Docs,它显示“bob :: impl _ :: XYZ”而不是“bob :: XYZ”。)
  2. 我想,重复std :: a并不是很干。秒。 O操作。无处不在。我也理解在较大范围(例如类)中相对全局的“使用命名空间std”并不那么美,但在我看来,数百个std ::前缀更加丑陋。这是哪种方法更好?
c++ c++11 namespaces coding-style
1个回答
5
投票

让我们假设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
}

现在,查理发明了一个名为foobar的新功能,并将其添加到他的库中。 foobar很棒,他的用户喜欢它。 Alice也开始使用它。

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

哦,哦,现在爱丽丝的代码无法编译! Alice的代码中foobar的每次使用都是模棱两可的,她必须重写她的整个项目。

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

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

爱丽丝向鲍勃和查理发送电子邮件说

伙计们,你必须停止制作同名的课程,否则我将失去我的所有业务!

Bob和Charlie发回电子邮件给Alice:

没有爱丽丝,你需要停止在你的代码中加入using namespace bob;using namespace charlie;。鲍勃或查理不支持这一点。


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


简而言之,using namespace指令从来都不是一个好主意(在我看来)。特别是当命名空间是外部库时。你真的不知道这个命名空间将来会如何变化,如果它以一种对你有害的方式发生变化,你的手上会突然变得非常混乱。

使用namespace =缩短命名空间通常是一个非常好的主意。我喜欢做以下事情:

namespace my_lib {

namespace qi = boost::spirit::qi;

// Do stuff with qi
// ...

} // end namespace my_lib

这样我就可以在qi中使用短名称my_lib,但我没有对我的用户强加任何东西。 (我期望谁不会做using namespace my_lib;!)

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

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

但是,您应该非常乐意键入bob::std::这样的短命名空间,无论您是用户还是库实现者,如果它意味着您的代码在升级库时不会中断。

这不是DRY。在名称上放置某种限定符可以更容易地阅读代码并理解它的含义。

例如,看一下流行的C库SDL。据我所知,SDL中的每个宏开始SDL_,每个函数都开始sdl_。这是违反“干”的吗?没有。这里没有重复的实现细节 - 公共前缀是为了避免名称冲突。此外,它使代码更具可读性和可维护性 - 每当我看到一个正在谈论SDL实体的符号时,我立即就知道了。它对人类和计算机都非常有帮助。

using namespace std;using namespace my_lib;放在C ++最佳功能之一就把它丢进垃圾箱里。权衡的是,除了键入5个字符外,还要以损害可读性和可维护性为代价。


分手思考:using namespace如何影响您获得的错误消息的质量。

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

#include <iostream>

struct foo {};

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

当编译器看到这个代码时,它将不得不尝试它知道的每个流操作符重载并检查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;
                    ^

这就是重点:如果你做using namespace bob;,那么每个bob的可流动类型也将出现在该列表中!如果你做using namespace charlie;那么他的所有类型也将在那里!

错误消息不仅会更糟糕,而且您更有可能获得一些您没想到的非常奇怪的交互。如果Bob的类型偶尔可以链接到Charlie的类型之一怎么办?查理的类型偶尔可以隐式转换为可流化的标准类型?

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

所以,最重要的是,如果你避免在一个命名空间中混合大量垃圾,那么C ++就更容易推理并且工作得更好。

© www.soinside.com 2019 - 2024. All rights reserved.