jjzjj

c++ - C++命名空间的困扰

coder 2024-02-08 原文

好的,这个问题有所发展,我想尝试着(从)开始为我所追求的基本目标:

  • 创建用于包装C++资源获取中的传统C语言实体的库代码是初始化的,还提供了基本或更好的异常保证。
  • 允许此代码的客户端以非常自然的C++方式使用它,而不会给现有代码带来很多开销,从而无法将其转换为使用C++包装器对象(即自动转换为适当的旧类型,采用旧类型的构造函数,等)
  • 限制库代码对 namespace 的影响。理想情况下,该库将具有几个子命名空间,这些子命名空间提供相关的功能,这些功能会限制使用命名空间X类型声明的数量和影响-就像boost库所做的一样(即,使用details命名空间仅注入(inject)用户合理想要的那些符号使用并隐藏实现细节;也将可能的新含义限制在现有符号范围内,以避免在用户代码内进行令人惊讶的隐式转换)
  • 要求客户端明确要求他们实际上要注入(inject)到其代码库中的库部分。这与限制包含库 header 的影响紧密相关。客户端代码应具有合理的控制级别,以控制库的哪些部分在编译代码时将自动用于名称解析。
  • 我自己的库代码不应该被那些易碎的代码结构所困扰。如果库的 header 不必经常声明私有(private)typedef以便访问库的其余部分,那将是理想的。或者换句话说:我希望我的库能够像使用该库时客户所能理解的那样直观地编写。名称解析应该包括在库中定义的 namespace ,以及其他任何已明确“使用”的 namespace 。

  • 我经常遇到这种情况,并且正在寻找更好的方法...

    我在命名空间N中有一个类C。C有一个成员Free。它释放了C所管理的东西,并允许C来管理新事物。

    有几个全局Free功能。在与C相同的命名空间N中也有一些辅助函数,其中之一是一个释放由C管理的东西的助手,名为free。

    所以我们有这样的东西:
    namespace N {
    
    void free(THING * thing);
    
    class C
    {
    public:
      ... details omitted...
      free()
      { 
        free(m_thing); // <- how best to refer to N::free(THING&)
      }
    }
    
    } // namespace N
    

    我可以使用N::free(m_thing)。但这对我来说很不幸。有没有办法引用超出类范围但没有解决绝对 namespace 的问题(从范围的角度出发相对一步)?

    在我看来,必须将N::free命名是令人讨厌的,因为如果这是一个独立的函数,则不必这样做。如果类的方法名称碰巧是不同的(例如,dispose),则也不需要。但是,因为我使用了相同的名称,所以如果您不喜欢类比的话,就必须指定绝对路径而不是相对路径才能访问它。

    我讨厌绝对的道路。它们使在 namespace 中移动东西变得非常脆弱,因此代码重构变得更加难看。另外,在函数主体中如何命名事物的规则随着当前的规则集(据我所知)变得更加复杂-不那么规则-导致人们期望与程序员之间达成 split 。

    是否有更好的方法可以在与类相同的 namespace 中访问独立函数,而不必绝对命名自由函数?

    编辑:
    也许我应该举一个不太抽象的例子:
    namespace Toolbox {
      namespace Windows {
    
    // deallocates the given PIDL
    void Free(ITEMIDLIST ** ppidl);
    
    class Pidl
    {
    public:
        // create empty
        Pidl() : m_pidl(NULL) { }
    
        // create a copy of a given PIDL
        explicit Pidl(const ITEMIDLIST * pidl);
    
        // create a PIDL from an IShellFolder
        explicit Pidl(IShellFolder * folder);
    
        ...
    
        // dispose of the underlying ITEMIDLIST* so we can be free to manage another...
        void Free();
    };
    

    因此,ITEMIDLIST *来自各个地方,并被CoTaskMemFree()销毁。我可以将Pidl引入为全局名称-以及工具箱库中的“Windows Shell.h” header 中的所有辅助函数。

    理想情况下,我将库中的某些工具按它们所关联的内容进行 segmentation -在这种情况下,以上所有内容均与Windows中的COM编程有关。我已经选择了Toolbox作为我的库东西的基本命名空间,并且目前正在考虑使用Windows -y函数,类等Toolbox::Windows。

    但是C++命名空间和名称解析规则似乎使这一点变得非常困难(因此出现了这个问题)。创建代码的这种分段非常不自然-因为koenig查找失败(因为ITEMIDLIST不在我的Toolbox::Windows命名空间中),并且我无法将其移到那里!我也不应该。该语言应该足够灵活,IMO,以允许扩展库(例如我的Toolbox库)扩展其他人的代码,而不必将扩展名插入其命名空间(对于Win32和一般今天存在的大多数代码是GLOBAL NS-首先是创建 namespace 的全部要点:避免全局NS拥挤/污染/歧义/编程意外。

    所以,我回到那里是否有更好的方法:扩展现有的代码库,同时不使用扩展名污染它们的NS,但仍然允许直观和有用的名称解析,就像我的代码在它们的内部一样。 NS,但是由我的代码的客户端明确引入的(即,我不想随意插入我的代码,而仅在明确请求的情况下)?

    另一个想法:如果我具有以下条件,也许满足我上面的要求:
    using namespace X {
      code here...
    }
    

    我可以在任何地方(包括 header 中)放置这样的构造,而不必担心将X拖到客户的代码中,但是我可以自由地编写源代码,就像在源代码中一样。根 namespace 。

    最佳答案

    我认为这里不必避免限定 namespace 范围的free(),但应注意,这与“绝对路径”不同。一方面,如果您具有嵌套的 namespace ,则只需引用最里面的一个:

    namespace N1 {
      namespace N2 {
        namespace N3 {
          void free(THING * thing);
    
          class C {
          public:
            free() {
              N3::free(m_Thing); // no need to do N1::N2::
            }
          };
        }
      }
    }
    

    [编辑] ,以响应已编辑的问题。同样,在您描述的确切情况下,我看不到有任何方法可以做到这一点。但是,这似乎不是C++惯用的方法-进行此操作的更常见方法是为ITEMIDLIST提供您自己的包装器类,以管理RAII样式的所有分配并公开原始句柄(例如,通过转换运算符a ATL,或者如果需要额外的安全性,则可以使用像c_str()这样的显式成员函数)。这将完全不需要free,也不需要那里的任何其他自由函数,因为您可以控制包装器类型及其所在的 namespace ,因此可以照常使用ADL。

    [EDIT#2] 。问题的这一部分:

    allow for intuitive and useful name resolution as one would expect if my code were in their NS but explicitly introduced by the client of my code (i.e. I don't want to inject my code willy-nilly, but only upon explicit request)?



    您将它放在命名空间中并由客户编写using namespace ...来实现就可以了吗?

    关于c++ - C++命名空间的困扰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1902651/

    有关c++ - C++命名空间的困扰的更多相关文章

    1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    2. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

      当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

    3. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

      我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

    4. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    5. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

      我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

    6. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

      Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

    7. ruby - 如何计算 Liquid 中的变量 +1 - 2

      我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

    8. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    9. ruby - 使用 Nokogiri 和 Ruby 命名元素 "text" - 2

      我在尝试使用Nokogiri构建XML文档时遇到了一个小问题。我想将我的元素之一称为“文本”(请参阅​​下面粘贴代码的最底部)。通常,要创建一个新元素,我会执行类似以下的操作xml.text--但它似乎是.text是Nokogiri已经用来做其他事情的方法。因此,当我写这行时xml.textNokogiri没有创建名为的新元素但只是写了意味着成为元素内容的文本。我怎样才能让Nokogiri实际制作一个名为的元素??builder=Nokogiri::XML::Builder.newdo|xml|xml.TEI("xmlns"=>"http://www.tei-c.org/ns/1.0"

    10. += 的 Ruby 方法 - 2

      有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

    随机推荐