现象
- 报错: 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();
现象
定位过程
原因分析
clang++在处理pmr命名空间时的报错,这并不是工具的问题,而是由于clang++对C++标准中两阶段名称查找(Two-PhaseLookup)的执行更为严谨、规范。
在模板代码中,当使用->访问 模板类 的成员时,clang++为了确保代码的安全性和标准化,会严格限制解析范围。在这种模糊语境下,它不会主动去全局作用域寻找命名空间别名,以防止潜在的符号冲突。相比之下,g++的处理方式较为宽松。消除这种模糊性,建议采用符合标准的显式写法。
解决方式
修改前:
修改后:
或者显式指明为命令空间