Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ #在名称空间中包括到;嵌入;名称空间中的预写内容_C++_Templates_Namespaces - Fatal编程技术网

C++ #在名称空间中包括到;嵌入;名称空间中的预写内容

C++ #在名称空间中包括到;嵌入;名称空间中的预写内容,c++,templates,namespaces,C++,Templates,Namespaces,简介:这样做安全吗 namespace Foo { #include "bar" } 在你愉快地说不之前,我想我有一些规则可以让它相当安全 但我不喜欢它们,因为它们要求includer单独包含所需的所有全局范围头。尽管这可能是可以容忍的,但如果我们设想在名称空间中包含只是一种特殊的管理特性的话 总的来说,外部和转发声明在名称空间中不能很好地工作 所以我问你 a) 还有什么别的陷阱 b) 有更好的办法吗 ==一个[[仅标题库]]== 我喜欢写图书馆。[[仅标题库和链接器库]] 例如 为简单

简介:这样做安全吗

 namespace Foo {
 #include "bar"
 }
在你愉快地说不之前,我想我有一些规则可以让它相当安全

但我不喜欢它们,因为它们要求includer单独包含所需的所有全局范围头。尽管这可能是可以容忍的,但如果我们设想在名称空间中包含只是一种特殊的管理特性的话

总的来说,外部和转发声明在名称空间中不能很好地工作

所以我问你

a) 还有什么别的陷阱

b) 有更好的办法吗

==一个[[仅标题库]]==

我喜欢写图书馆。[[仅标题库和链接器库]]

例如

为简单包装器类型定义有效的模板

<>(不要陷入“你应该使用一些标准库来代替这个,这是一个例外。我不知道Boost还是C++已经把这个标准化了。我一直在使用包装,因为模板被添加到C++中。” 另外,假设它是一个只包含标题的库,它在Valid.hpp中定义, 打印函数

std::字符串到_字符串(常量有效(&v){ std::ostringstream oss;
如果(v.valid()){oss我认为这是不安全的。您将所有包含项都放在名称空间Foo中。。。 想象一下,您的一些包含来自std名称空间的内容……我无法想象会有多么混乱


我不会这么做。

头文件不是黑盒。您可以随时查看项目中包含的头文件,看看是否可以安全地将其包含在命名空间块中。或者更好的是,您可以修改头文件本身以添加命名空间块。即使头文件来自第三方库,并且在后续版本中进行了更改e、 你的项目中的标题不会更改。

我知道这是一个老问题,但我想给出一个更详细的答案。另外,请给出潜在问题的真实答案

如果您在名称空间中包含一个头,这里有一些可能会出错的地方

  • 标头包含其他标头,这些标头随后也包含在命名空间内。然后,另一个位置也希望包含这些标头,但来自命名空间外。由于标头具有包含保护,因此实际上只有一个包含生效,并且标头中定义的内容的实际命名空间突然出现y微妙地取决于包含其他标题的顺序

  • 标头或其包含的任何标头应位于全局命名空间中。例如,标准库标头通常(为了避免冲突)引用其他标准内容(或实现详细信息)作为
    ::std::other_stuff
    ,即,期望
    std
    直接位于全局名称空间中。如果您在名称空间中包含标题,则情况不再如此。此内容的名称查找将失败,标题将不再编译。而且它不仅仅是标准标题;我确信在增压头也是如此

  • 如果您首先通过确保包含所有其他标题来解决第一个问题,然后通过确保没有使用完全限定的名称来解决第二个问题,那么事情仍然会出错。一些库要求其他库专门化它们的内容。例如,库可能要专门化
    std::swap
    std::哈希
    std::less
    用于它自己的类型。(您可以重载
    std::swap
    ,但不能重载
    std::hash
    std::less
    )方法是关闭库特定的命名空间,打开命名空间
    std
    ,并将专门化放在那里。除非库的头包含在任意深度嵌套的命名空间中,否则它无法关闭这些命名空间。它试图打开的命名空间
    std
    将不是
    ::std
    ,而是
    :您的命名空间tuff::std
    ,它可能不包含任何要专门化的主模板,即使它包含了,也仍然是错误的

  • 最后,名称空间中的内容与外部内容的名称不同。如果您的库不只是标题,而是有一个已编译部分,则已编译部分可能没有将所有内容嵌套在名称空间中,因此库中的内容与您刚才包含的内容具有不同的名称。换句话说,您的程序将无法链接。

    因此,从理论上讲,您可以设计包含在名称空间中的标题,但它们使用起来很烦人(必须冒泡出对includer的所有依赖项),而且非常受限(不能使用完全限定名或专门化另一个库名称空间中的内容,必须仅为标题)。所以不要这样做

    但是您有一个不使用名称空间的旧库,您希望在不破坏所有旧代码的情况下对其进行更新以使用它们。下面是您应该做的:

    首先,将子目录添加到库的include目录中。将其称为“namespaced”或类似的名称。接下来,将所有头移动到该目录中,并将其内容包装到名称空间中

    然后将转发头添加到基本目录。对于库中的每个文件,添加如下所示的转发器:

    #ifndef YOURLIB_LEGACY_THE_HEADER_H
    #define YOURLIB_LEGACY_THE_HEADER_H
    
    #include "namespaced/the_header.h"
    using namespace yourlib;
    
    #endif
    
    现在,旧代码应该像往常一样工作


    对于新代码,技巧是不包括“namespaced/the_header.h”,而是更改项目设置,使include目录指向namespaced子目录而不是库根目录。然后,您可以简单地包括“the_header.h”“并获取名称空间的版本。

    我将另外问一个问题,关于仅标题库的最佳用户模式。最新问题:名称冲突会发生……安全吗?当然。例如,如果“bar”是一个空文件,那么它肯定是安全的。但是,通常情况下,如果您不安全
       Valid.hpp:
    
             #include <iostream>
             #include <sstream>
    
             template<typename T> 
             class Valid {
             private:
               T value_;
               bool valid_
               ...
             };
    
             ...
    
             std::string to_string( const Valid<T>& v ) { ...
    
       namespace AG {
        namespace Wrapper {
        #include "lib/AG/Wrapper/Valid.hpp"
        }
        }
    
        AG::Wrapper::Valid<T> foo_v; 
    
        ...
    
       #include <iostream>
        #include <sstream>
    
        namespace AG {
        namespace Wrapper {
        #include "lib/AG/Wrapper/Valid.hpp"
        }
        }
    
        AG::Wrapper::Valid<T> foo_v; 
    
        ...
    
     Type var;
    
     namespace Foo {
     void bar() {
        extern ::Type      ::var;;
        extern ::Type      ::Foo::bar;
        extern ::Type::foo      ::bar;  // see the ambiguity?
     };
    
     namespace Foo {
     void bar() {
        extern int var;
     };
    
    namespace A {
    void foo() {
       // --- here is a reference to gloal scope extreren ...
    
    #ifndef YOURLIB_LEGACY_THE_HEADER_H
    #define YOURLIB_LEGACY_THE_HEADER_H
    
    #include "namespaced/the_header.h"
    using namespace yourlib;
    
    #endif