如何让C++方法同时兼容const指针引用与非const指针引用?
让UTF-8码点读取函数同时支持const和非const指针引用
我有几个辅助方法通过引用接收指针,在满足特定条件时将其向前移动。示例如下:
char32_t readCodePoint(const char8_t *¤t, const char8_t *end) { assert((current < end) && u8"At least one byte of input must be available"); char8_t leadCharacter = *current; if(leadCharacter < 128) { ++current; return static_cast<char32_t>(leadCharacter); } else if((leadCharacter & 0xE0) == 0xC0) { // ...处理2、3、4字节码点的代码已省略... // (均会相应递增'current'并遵守'end'的限制) } // 序列无效或被截断 return char32_t(-1); }
目前该方法仅支持const char8_t *指针,但强制要求指针为const类型,以下代码会触发编译错误:
void collapseDuplicateWhitespace(std::u8string &utf8String) { char8_t *current = utf8String.data(); char8_t *end = current + utf8String.length(); while(current < end) { // 错误:'current'是'char8_t *'而非'const char8_t *' char32_t codePoint = readCodePoint(current, end); // ...其他逻辑已省略... } // ...将字符串调整为新的更短长度... }
显然,const_cast的结果无法直接作为引用传递,这会导致调用端代码十分丑陋,甚至在发布版本中引入别名问题。
请问是否存在一种优雅且可读性良好的方式,修改该方法使其同时支持const char8_t *&和char8_t *&作为current的类型?
解决方案:模板化函数
将readCodePoint改成模板函数,让编译器自动推导指针的const修饰符,即可同时兼容两种指针类型:
#include <type_traits> template <typename Char8Ptr> char32_t readCodePoint(Char8Ptr ¤t, const char8_t *end) { // 限制仅接受char8_t*或const char8_t*类型 static_assert(std::is_same_v<std::remove_const_t<Char8Ptr>, char8_t*>, "Char8Ptr must be char8_t* or const char8_t*"); assert((current < end) && u8"At least one byte of input must be available"); char8_t leadCharacter = *current; if(leadCharacter < 128) { ++current; return static_cast<char32_t>(leadCharacter); } else if((leadCharacter & 0xE0) == 0xC0) { // ...处理2、3、4字节码点的代码... // 同样递增current即可,模板会保留原指针的const属性 } // 序列无效或被截断 return char32_t(-1); }
核心优势
- 自动类型适配:编译器会根据传入的
current类型(char8_t*或const char8_t*)自动实例化对应版本,无需手动编写重载。 - 类型安全:通过
static_assert限制模板仅接受合法的指针类型,避免误用其他指针导致的错误。 - 无冗余代码:模板化实现只需维护一份核心逻辑,避免重载带来的代码重复。
备选方案:手动重载
如果不想使用模板,也可以手动提供两个重载函数,通过复用const版本的逻辑实现:
// 非const版本 char32_t readCodePoint(char8_t *¤t, const char8_t *end) { const char8_t* const_current = current; char32_t result = readCodePoint(const_current, end); current = const_cast<char8_t*>(const_current); return result; } // 原有的const版本保持不变 char32_t readCodePoint(const char8_t *¤t, const char8_t *end) { // 原逻辑... }
不过这种方式需要额外维护重载函数,代码复用性不如模板方案。
内容的提问来源于stack exchange,提问作者Cygon
相关产品推荐
相关产品推荐

