使用C++20 Concepts约束函数参数为分配器的问题排查
分配器概念不成立的原因及修正方案
你的is_allocator概念无法识别任何分配器,主要有三个核心问题:
1. deallocate参数类型错误
概念中deallocate的第一个参数使用了std::declval<typename Allocator::value_type>(),但所有标准分配器的deallocate方法接收的第一个参数是指针类型(value_type*),而非值类型。这直接导致所有合法分配器都无法满足该约束。
2. 未考虑成员函数的const属性
标准分配器(如std::allocator)的allocate和deallocate都是const成员函数,但你在requires表达式中使用非const的分配器对象调用这些方法,无法匹配到const成员函数,因此概念不成立。
3. std::pmr::polymorphic_allocator的特殊适配问题
std::pmr::polymorphic_allocator的allocate是模板成员函数,无法直接通过a.allocate(n)的形式调用(需要显式指定模板参数),直接调用会导致编译失败,进而无法满足概念约束。
修正方案
方案1:适配标准非PMR分配器
针对前两个问题修正概念,可识别std::allocator和自定义MyAllocator:
#include <iostream> #include <string> #include <memory> #include <memory_resource> #include <vector> #include <concepts> #include <utility> #include <cstdlib> template <typename Allocator> concept is_allocator = requires(const Allocator& a, typename Allocator::value_type* ptr, std::size_t n) { typename Allocator::value_type; { a.allocate(n) } -> std::same_as<typename Allocator::value_type*>; { a.deallocate(ptr, n) } -> std::same_as<void>; }; template <typename T> struct MyAllocator { using value_type = T; // 补充const修饰,匹配标准分配器的成员函数属性 auto allocate(std::size_t size) const -> T* { return static_cast<T*>(std::malloc(size * sizeof(T))); } auto deallocate(T* ptr, std::size_t) const -> void { std::free(ptr); } }; int main() { using A1 = std::allocator<int>; using A2 = std::pmr::polymorphic_allocator<std::byte>; using B = MyAllocator<int>; using C = std::string; if constexpr(is_allocator<A1>) { std::cout << "A1 is an allocator" << std::endl; } if constexpr(is_allocator<B>) { std::cout << "B is an allocator" << std::endl; } // A2 仍无法通过,因为它的allocate是模板函数 if constexpr(is_allocator<A2>) { std::cout << "A2 is an allocator" << std::endl; } if constexpr(is_allocator<C>) { std::cout << "C is an allocator" << std::endl; } }
方案2:兼容PMR分配器(推荐)
利用std::allocator_traits标准工具,适配所有符合分配器规范的类型(包括PMR分配器):
#include <iostream> #include <string> #include <memory> #include <memory_resource> #include <vector> #include <concepts> #include <utility> #include <cstdlib> template <typename Allocator> concept is_allocator = requires { typename std::allocator_traits<Allocator>::value_type; typename std::allocator_traits<Allocator>::pointer; } && requires(const Allocator& a, std::size_t n, typename std::allocator_traits<Allocator>::pointer p) { { std::allocator_traits<Allocator>::allocate(a, n) } -> std::same_as<typename std::allocator_traits<Allocator>::pointer>; std::allocator_traits<Allocator>::deallocate(a, p, n); }; template <typename T> struct MyAllocator { using value_type = T; auto allocate(std::size_t size) const -> T* { return static_cast<T*>(std::malloc(size * sizeof(T))); } auto deallocate(T* ptr, std::size_t) const -> void { std::free(ptr); } }; int main() { using A1 = std::allocator<int>; using A2 = std::pmr::polymorphic_allocator<std::byte>; using B = MyAllocator<int>; using C = std::string; if constexpr(is_allocator<A1>) { std::cout << "A1 is an allocator" << std::endl; } if constexpr(is_allocator<A2>) { std::cout << "A2 is an allocator" << std::endl; } if constexpr(is_allocator<B>) { std::cout << "B is an allocator" << std::endl; } if constexpr(is_allocator<C>) { std::cout << "C is an allocator" << std::endl; } }
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

