【问题标题】:Add a new namespace in API backwards compatible way以 API 向后兼容的方式添加新的命名空间
【发布时间】:2022-01-01 05:09:08
【问题描述】:

这个公共类有一个库。

namespace lib {
class Class {};
}

我想重构它并添加一个更多的命名空间。

namespace lib::sublib {
class Class {};
}

我想让它的 API 向后兼容,这样现有的库客户端就可以在不更改代码的情况下使用新的库版本进行编译。我尝试添加别名。

namespace lib {
using Class [[deprecated]] = sublib::Class;
}

这在大多数情况下都有效,除非库客户端转发声明 lib::Class

namespace lib {
class Class;
}

在这种情况下,存在声明冲突的错误。

<source>: error: conflicting declaration 'using Class = class lib::sublib::Class'
   10 |     using Class = sublib::Class;
      |           ^~~~~
<source>: note: previous declaration as 'class lib::Class'
    2 |     class Class;
      |           ^~~~~

有没有办法添加一个新的命名空间而不破坏现有的代码?这个问题仅与 API 有关。不需要 ABI 向后兼容。

【问题讨论】:

标签: c++ namespaces c++17 refactoring forward-declaration


【解决方案1】:

命名空间(内联或非内联)和类别名不是符号链接。

没有办法将类的实际定义移动到不同的命名空间,同时使先前命名空间中该类声明的所有使用有效。您可以使类名的大多数使用有效,但涉及类声明的使用无效。

一个类只存在于一个地方,该类的所有声明必须同意它所在的位置。当您可以访问该名称时,可能还有其他位置,但声明必须选择它的实际位置。

所以你要么不能移动这个类声明,要么你必须接受转发声明这个类的用户在你移动它时会受到破坏。

【讨论】:

    【解决方案2】:

    有一个很好的规则是永远不要将“使用命名空间”放在头文件中。 但是对于到新命名空间的过渡期,它确实可以提供帮助。 如果你这样做,那么你可以开始添加编译器选项宏 USE_MY_API_NAMESPACE 一次一个客户端项目。然后开始在需要的地方添加 new_namespace:: 到客户端代码。

    // header file
    #pragma once 
    
    // your new namespace
    namespace new_namespace
    {
        // your current api
        void api_func();
    }
    
    // even though using namespace isn't recommended
    // during transition it won't make things worse
    // since the existing API is in the global namespace anyway
    // just don't forget to add removing these lines
    // as technical debt to your project bugtracking database.
    
    #ifndef USE_MY_API_NAMESPACE
    using namespace new_namespace;
    #endif 
    
    // end of header file
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-17
      • 2021-10-10
      • 1970-01-01
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 2021-12-27
      • 2020-06-04
      相关资源
      最近更新 更多