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

2023-12-13

我们假设,Bob已将他的库包装到名称空间中"bob", and Alice将使整个命名空间在她自己的函数中可见“使用命名空间鲍勃”,代替“使用鲍勃::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;
}

另一方面,鲍勃试图通过以下方式防止这种情况发生:将实现包装在虚拟命名空间内,并制作只有这些符号可用,供其他用户使用:

// 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 指令都被包装到 Bob 主命名空间内的虚拟“impl_”命名空间中,因此 Alice 不存在以下风险:意外地从 std:: 命名空间导入符号, too.

所以,我的问题是:

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

我们假设Alice正在使用两个库,由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
}

现在,查理发明了一项新功能,称为foobar他将其添加到他的图书馆中。foobar很棒,他的用户喜欢它。爱丽丝也开始使用它。

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

呃哦,现在 Alice 的代码无法编译!每次使用foobarAlice 的代码中的内容不明确,她必须重写整个项目。

然后,下个月也会发生同样的事情。在那之后的下个月。

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

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

伙计们,你们必须停止用相同的名字制作课程,否则我会失去我所有的生意!

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

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


现在,让我们再讲一遍同样的故事,只不过没有查理。只是爱丽丝在她的项目中创建了自己的类,与鲍勃添加的新名称发生了冲突。


简而言之,一个using namespace指令从来都不是一个好主意(在我看来)。尤其当命名空间是外部库时。你不really知道该名称空间将来会如何变化,如果它的变化对您来说完全不利,那么您的手上就会突然陷入一团糟。

Using namespace = to shorten命名空间通常是一个非常好的主意。我喜欢做以下事情:

namespace my_lib {

namespace qi = boost::spirit::qi;

// Do stuff with qi
// ...

} // end namespace my_lib

这样我就可以使用简称qi in my_lib,但我不会向我的用户强加任何东西。 (我期望谁会not正在做using namespace my_lib;!)

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

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

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

这与 DRY 无关。推杆some名称上的某种限定符可以让您更轻松地阅读代码并理解其含义。

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

Putting using namespace std; or 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;那么他所有的类型也会在那里!

不仅错误消息会更糟糕,而且您更有可能得到一些您没有预料到的非常奇怪的交互。如果鲍勃的类型偶尔会流式传输到查理的类型之一怎么办? Charlie 的类型有时可以隐式转换为某种可流式传输的标准类型?

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

因此,最重要的是,如果您避免在一个名称空间中混合大量垃圾,C++ 会更容易推理并且工作得更好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 C++ 中防止名称空间中毒的优雅方法 的相关文章

  • MEX 文件中的断言导致 Matlab 崩溃

    我正在使用mxAssert 宏定义为matrix h在我的 C 代码中 mex 可以完美编译 当我调用的 mex 代码中违反断言时 该断言不会导致我的程序崩溃 而是导致 Matlab 本身崩溃 我错过了什么吗 这是有意的行为吗 当我查看 M
  • 添加对共享类的多个 WCF 服务的服务引用

    我正在尝试将我的 WCF Web 服务拆分为几个服务 而不是一个巨大的服务 但是 Visual Studio Silverlight 客户端 复制了两个服务共享的公共类 这是一个简单的例子来说明我的问题 在此示例中 有两个服务 两者都返回类
  • 在 C++ 中分割大文件

    我正在尝试编写一个程序 该程序接受一个大文件 任何类型 并将其分成许多较小的 块 我想我已经有了基本的想法 但由于某种原因我无法创建超过 12 kb 的块大小 我知道谷歌等上有一些解决方案 但我更感兴趣的是了解这个限制的根源是什么 然后实际
  • 在 C++11 中省略返回类型

    我最近发现自己在 C 11 模式下的 gcc 4 5 中使用了以下宏 define RETURN x gt decltype x return x 并编写这样的函数 template
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • 调试内存不足异常

    在修复我制作的小型 ASP NET C Web 应用程序的错误时 我遇到了 OutOfMemoryException 没有关于在哪里查看的提示 因为这是一个编译时错误 如何诊断此异常 我假设这正是内存分析发挥作用的地方 有小费吗 Thank
  • VS30063:您无权访问 https://dev.azure.com

    我正在尝试在 asp net core 2 1 mvc 应用程序中使用以下代码连接 Azure DevOps Uri orgUrl new Uri https dev azure com xxxxx String personalAcces
  • C++11 函数局部静态 const 对象的线程安全初始化

    这个问题已在 C 98 上下文中提出 并在该上下文中得到回答 但没有明确说明有关 C 11 的内容 const some type create const thingy lock my lock some mutex static con
  • 如何用 kevent() 替换 select() 以获得更高的性能?

    来自Kqueue 维基百科页面 http en wikipedia org wiki Kqueue Kqueue 在内核和用户空间之间提供高效的输入和输出事件管道 因此 可以修改事件过滤器以及接收待处理事件 同时每次主事件循环迭代仅使用对
  • 在 C# 中将位从 ulong 复制到 long

    所以看来 NET 性能计数器类型 http msdn microsoft com en us library system diagnostics performancecounter aspx有一个恼人的问题 它暴露了long对于计数器
  • 禁用 LINQ 上下文的所有延迟加载或强制预先加载

    我有一个文档生成器 目前包含约 200 个项目的查询 但完成后可能会超过 500 个 我最近注意到一些映射表示延迟加载 这给文档生成器带来了一个问题 因为它需要根据生成的文档来访问所有这些属性 虽然我知道DataLoadOptions可以指
  • gdb 在 docker 上立即退出“进程已完成,退出代码 1”或 lldb“数据包返回错误 8”。另外:如何在 docker 中允许进行 C++ 调试

    这花了我一整天的时间才找到 所以我将其发布以供将来参考 我正在 docker 镜像上开发 C 我正在使用克利翁 我的代码是在调试模式下编译的 并且在运行模式下运行良好 但是当尝试调试时 进程会立即退出 并显示非常丰富的信息 Process
  • 单元测试失败,异常代码为 c0000005

    我正在尝试使用本机单元测试项目在 Visual Studios 2012 中创建单元测试 这是我的测试 TEST METHOD CalculationsRoundTests int result Calculations Round 1 0
  • 组合框项目为空但数据源已满

    将列表绑定到组合框后 其 dataSource Count 为 5 但组合框项目计数为 0 怎么会这样 我习惯了 Web 编程 而且这是在 Windows 窗体中进行的 所以不行combo DataBind 方法存在 这里的问题是 我试图以
  • 如何排列表格中的项目 - MVC3 视图 (Index.cshtml)

    我想使用 ASP NET MVC3 显示特定类型食品样本中存在的不同类型维生素的含量 如何在我的视图 Index cshtml 中显示它 an example 这些是我的代码 table tr th th foreach var m in
  • C# 搜索目录中包含字符串的所有文件,然后返回该字符串

    使用用户在文本框中输入的内容 我想搜索目录中的哪个文件包含该文本 然后我想解析出信息 但我似乎找不到该字符串或至少返回信息 任何帮助将不胜感激 我当前的代码 private void btnSearchSerial Click object
  • 无法使用 Ninject 将依赖项注入到从 Angular 服务调用的 ASP.NET Web API 控制器中

    我将 Ninject 与 ASP NET MVC 4 一起使用 我正在使用存储库 并希望进行构造函数注入以将存储库传递给其中一个控制器 这是实现 StatTracker 接口的上下文对象 EntityFramework public cla
  • SQL Server 2008:如何从元素中删除名称空间,但让它显示在根目录上

    我正在使用 SQL Server2008 FOR XML 子句使用 bcp 生成 XML 文件 当我使用下面的查询时 结果很好 WITH XMLNAMESPACES http base google com ns 1 0 AS g DEFA
  • 以编程方式使用自定义元素创建网格

    我正在尝试以编程方式创建一个网格 并将自定义控件作为子项附加到网格中 作为 2x2 矩阵中的第 0 行第 0 列 为了让事情变得更棘手 我使用了 MVVM 设计模式 下面是一些代码可以帮助大家理解这个想法 应用程序 xaml cs base
  • 从类模板参数为 asm 生成唯一的字符串文字

    我有一个非常特殊的情况 我需要为类模板中声明的变量生成唯一的汇编程序名称 我需要该名称对于类模板的每个实例都是唯一的 并且我需要将其传递给asm关键字 see here https gcc gnu org onlinedocs gcc 12

随机推荐

  • 谷歌地图 API v3 投影?

    我想知道谷歌地图使用什么投影是 EPSG 4326 还是 P900913 另外 如果您使用绘图工具 会生成什么投影坐标 EPSG3857是官方指定 交互式网络地图使用 球面墨卡托 系统 该系统使用墨卡托投影球体而不是 WGS84 椭球体 更
  • 全屏应用程序 WM6 C#

    谁能指导我如何使用 C 创建适用于 Windows Mobile 6 的全屏应用程序 我正在尝试实现与 Tom Tom 等应用程序类似的显示 其中隐藏了所有操作系统元素 例如开始 任务栏 并且我的应用程序完全填满了屏幕 我正在使用 VS 2
  • 连接到 BLE 设备

    所以我制作了这个应用程序 我可以在其中找到所有具有名称的 BLE 设备 但是我怎样才能使特定字段之一可单击并自动连接到设备 以便我可以开始从中写入 读取呢 Adapter public class ListAdapter BTLE Devi
  • 如何在Spritekit中创建风效果

    我在玩 愤怒的小鸟 到了这个阶段 风 吹 你 有点推你 有点有趣 但我真的无法弄清楚可以完成此操作的逻辑或代码 我知道你可能会使用发射器来创建像 看 一样的风 但我真的很想了解如何完成精灵的 推动 谢谢 你是对的 发射器只能用来产生风在吹的
  • 阅读:hover 伪类与 javascript

    我做了一个函数来覆盖 hover页面上的某些元素 它在正常和正常之间消失 hover 影响 因为我必须创建一个 hover我的 CSS 文件中的类 我觉得这有点不干净 我怎样才能读到 hover伪类内容 Using getComputedS
  • 使用 Cypher 2.0 将 Lucene 查询传递到 Neo4j REST API

    如果我有一个 Lucene 查询 例如 title foo bar AND body baz OR title bat有没有直接的方法可以将其传递到 Cypher 查询中 它看起来像这样用来工作START和旧的node auto index
  • 我可以像数组一样使用 stdClass 吗?

    是否可以使 stdClass 对象像通用索引数组一样工作 IE 数组 数组 0 gt 120 1 gt 382 2 gt 552 3 gt 595 4 gt 616 会被构造成像 a array array 120 array 382 et
  • 手动计算SVM的决策函数

    我正在尝试使用Python库SKLearn手动计算SVC分类器的decision function 而不是使用内置方法 我已经尝试了几种方法 但是 当我don t扩展我的数据 z是一个测试数据 已缩放 我认为其他变量本身就说明了问题 另外
  • 在新 Intent 中显示 TabHost 布局时出现问题

    我在 TabActivity 类型的新 Intent 中使用 TabHost 时遇到问题 希望您能为我指出正确的方向 有趣的是 当我尝试在原始意图中查看它时 它工作正常 setContentView R layout main 我收到 强制
  • 为什么我无法在 HTML 标签内插入注释?

    有什么原因导致我无法在 HTML 标记内插入注释吗 示例 HTML 格式 不可能 img src alt Sample Picture class img circle center block gt 而在 JavaScript 中 这可以
  • ServiceStack:存在时从目录提供静态文件吗?

    我正在将我的独立的自制 Web 服务器转换为使用 ServiceStack 来提供所有页面和资源 从这个问题我看出 使用 servicestack 提供静态文件 使用服务堆栈提供单个静态文件很容易 在我自己开发的实现中 在检查 URL 是否
  • WebRTC - 从 Chrome 但不是 Firefox 获取“格式错误的约束对象”

    我想知道我做错了什么 我从中收到 格式错误的约束对象 错误 pc createAnswer function answer fail offerToReceiveAudio true offerToReceiveVideo true 有任何
  • 处理十六进制之间的转换

    我想构建一个函数来轻松地将包含十六进制代码的字符串 例如 0ae34e 转换为包含等效 ascii 值的字符串 反之亦然 我是否必须将十六进制字符串切成两个值对 然后再次将它们组合在一起 或者是否有一种方便的方法可以做到这一点 thanks
  • C#:可空结构上的默认文字和类型推断

    从 C 7 1 开始 可以通过使用获取默认值default不指定类型 我今天尝试了一下 发现可为空结构和可为空值类型的结果有些违反直觉 TestFixture public class Test private class Person p
  • 将 10 位数字转换为十六进制字符串

    如何在 C 中将 10 位数字转换为十六进制字符串 Note 如果数字少于10位 我想添加填充 例子 数字是 1 我希望我的字符串是 0000000001 Use a 标准格式字符串 string paddedHex myNumber To
  • Eigen::Ref<> 作为成员变量

    我需要一个类有一个 Eigen Ref 变量作为静态成员 该变量将通过init静态方法 像这样的东西 class CostFunction public static Eigen Ref
  • 在 Google Analytics 中组合相似的 URL(有一些变化)

    我有很多类似的网址 我想将它们合并到 Google Analytics 分析 中 我已经成功地合并了其中的很多 然而我现在遇到了一些问题 我的 URL 看起来像这样 文章 4567 编辑文章 87478548 编辑 文章 82984786
  • 当您订阅ngrx中的商店时,如何访问以前的状态和当前状态并进行比较?

    在我的组件中 我订阅了 ngrx 存储 该存储在给定状态发生变化时触发 我想设置一个条件 如果当前状态和以前的状态不同 那么我会执行一些操作 如何获取之前的状态 this store select testPortfolio subscri
  • Android 视频方向在 mediarecorder.Start() 上发生变化

    这个问题和帖子类似here here here here and here 但我被困住了 花了几个小时试图弄清楚 我有一个摄像机预览 现在总是以正确的方向显示 但是当我点击录制 mediaRecorder start 时 视频方向会发生变化
  • 在 C++ 中防止名称空间中毒的优雅方法

    我们假设 Bob已将他的库包装到名称空间中 bob and Alice将使整个命名空间在她自己的函数中可见 使用命名空间鲍勃 代替 使用鲍勃 XYZ 对于每一个项目 This file is written by Alice include