C++模板类中Allocator被错误推断为const char*的原因排查
问题分析:
const char*的来源及解决方法 为什么Allocator被推导为const char*?
在代码的main函数中,URL myurl = "www.google.ch";这行触发了类模板实参推导(CTAD),编译器会尝试从初始化器匹配构造函数并推导模板参数:
你的
URL类有两个构造函数:- 构造函数1:
URL(Allocator allocator = {}),参数类型直接是模板参数Allocator - 构造函数2:
URL(std::string_view url, Allocator allocator = {}),第一个参数是std::string_view
- 构造函数1:
字符串字面量
"www.google.ch"的原生类型是const char*,它可以直接匹配构造函数1的参数(无需任何类型转换);而匹配构造函数2需要先把const char*隐式转换为std::string_view,属于间接匹配。编译器会优先选择匹配度更高的构造函数1,因此推导
Allocator = const char*,同时StringType使用默认值std::string,最终实例化出URL<std::string, const char*>。
当Allocator是const char*时,Query结构体中尝试调用std::allocator_traits<const char*>进行rebind操作,但const char*根本不是标准分配器类型,自然会触发编译错误。
修复方案
方案1:将第一个构造函数声明为explicit
explicit关键字会禁止构造函数用于拷贝初始化,这样URL myurl = "www.google.ch";就只能匹配构造函数2,编译器会将const char*转换为std::string_view,同时使用默认的StringType和Allocator:
template <typename StringType = std::string, typename Allocator = typename StringType::allocator_type> struct URL { // 添加explicit关键字 explicit URL(Allocator allocator = {}) : mystr{ allocator} {} URL(std::string_view url, Allocator allocator = {}) : URL(allocator) { mystr = url; } Query<StringType, Allocator> query; StringType mystr; };
方案2:给第一个构造函数添加分配器类型约束(C++20及以上)
通过C++20的concept限制Allocator必须是合法的分配器类型,避免编译器将非分配器类型推导为Allocator:
#include <concepts> template <typename StringType = std::string, typename Allocator = typename StringType::allocator_type> struct URL { // 约束Allocator必须是StringType的分配器 URL(std::allocator_for<StringType> auto allocator = {}) : mystr{ allocator} {} URL(std::string_view url, Allocator allocator = {}) : URL(allocator) { mystr = url; } Query<StringType, Allocator> query; StringType mystr; };
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

