Skip to content

namespace undeclared #26

@lfeng14

Description

@lfeng14

现象

  • 报错: undeclared identifier pmr
  • 构建命令
    clang++ -std=gnu++11 dispatcher.cpp -o test_clang -I .  
    
  • pmr在c++17标准已支持pmr,但因为想使用 依赖库boost内的pmr类,所以构建时降低了c++标准,指定c++标准为gnu++11
  #if __cplusplus < 201703L
  #include <boost/container/pmr/monotonic_buffer_resource.hpp>
  namespace std {
  	namespace pmr = boost::container::pmr; # 命令空间别名
  }
  #endif

定位过程

  • 小例子模仿 用户代码:dispatcher.cpp -引用-> monotonic_object_pool.hpp -引用-> preprocessor.hpp -引用-> cpp17_feature.hpp -引用-> boost/container/pmr/monotonic_buffer_resource.hpp
    [root@localhost debug]# cat dispatcher.cpp
    #include <memory>
    #include "monotonic_object_pool.hpp"
    
    
      int main() {
        ObjectWrapperHeadWithBuff<int> obj; # 显式实例化才会报错
        ObjectChunkHead<int>::DeltaWithBuff(reinterpret_cast<int*>(&obj));
        return 0;
      }
    
    [root@localhost debug]# cat monotonic_object_pool.hpp
    #include <preprocessor.hpp>
    
    template<typename T>
    struct ObjectChunkHead;
    
    template<typename T>
    struct ObjectWrapperHeadWithBuff {
        pmr::monotonic_buffer_resource buff_;
        ObjectChunkHead<T> *chunk_head_;
    };
    
    
    template<typename T>
    struct ObjectChunkHead {
     static std::size_t object_offset_with_buff;
    
      static int *DeltaWithBuff(T *obj) {
        auto wrapper_head_ptr = 
            reinterpret_cast<ObjectWrapperHeadWithBuff<T> *>(
               reinterpret_cast<unsigned char *>(obj) - 
               object_offset_with_buff);
    
         std::addressof(wrapper_head_ptr->buff_)
            ->pmr::monotonic_buffer_resource::
                ~monotonic_buffer_resource();
         return 0;
      }
    
    };
    
    
    [root@localhost debug]# cat preprocessor.hpp
    #include <cpp17_feature.hpp>
    
    namespace {
      namespace pmr = std::pmr;
    }
    
    [root@localhost debug]# cat cpp17_feature.hpp
    #ifndef SPOCK_CPP17_FEATURE_HPP
    #define SPOCK_CPP17_FEATURE_HPP
    
    #if __cplusplus < 201703L
    
    #include <boost/container/pmr/monotonic_buffer_resource.hpp>
    
    namespace std {
    namespace pmr = boost::container::pmr;
    }
    
    #endif
    #endif
    
    [root@localhost debug]# cat boost/container/pmr/monotonic_buffer_resource.hpp
    // boost/container/pmr/monotonic_buffer_resource.hpp
    #ifndef MONOTONIC_BUFFER_RESOURCE_HPP
    #define MONOTONIC_BUFFER_RESOURCE_HPP
    
    
    namespace boost {
    namespace container {
    namespace pmr {
    
    class monotonic_buffer_resource {
    public:
        monotonic_buffer_resource() = default;
        ~monotonic_buffer_resource() = default;
        monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
        monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
    };
    
    } // namespace pmr
    } // namespace container
    } // namespace boost
    
    #endif
    

原因分析

  • clang++在处理pmr命名空间时的报错,这并不是工具的问题,而是由于clang++对C++标准中两阶段名称查找(Two-PhaseLookup)的执行更为严谨、规范。

  • 在模板代码中,当使用->访问 模板类 的成员时,clang++为了确保代码的安全性和标准化,会严格限制解析范围。在这种模糊语境下,它不会主动去全局作用域寻找命名空间别名,以防止潜在的符号冲突。相比之下,g++的处理方式较为宽松。消除这种模糊性,建议采用符合标准的显式写法。

解决方式

  • 在C++中,通过指针调用析构函数时,编译器会自动在对象的类作用域内查找。去掉前面的pmr::...路径即可。

修改前:

std::addressof(wrapper_head_ptr->buff_)
    ->pmr::monotonic_buffer_resource::~monotonic_buffer_resource();

修改后:

std::addressof(wrapper_head_ptr->buff_)
    ->~monotonic_buffer_resource(); 

或者显式指明为命令空间

std::addressof(wrapper_head_ptr->buff_)
    ->::pmr::monotonic_buffer_resource::~monotonic_buffer_resource();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions