C++中如何保留指针构造同时优先调用编译时推导长度的构造函数?
让BasicCharp优先使用数组构造函数(C++17方案)
问题背景
现有如下BasicCharp模板类,包含两个构造函数:
template <class CharType> class BasicCharp { public: using value_type = CharType; using pointer = value_type*; // 构造函数1:接受数组引用,编译时推导长度 template<size_t SIZE> constexpr BasicCharp(value_type (&str)[SIZE]) noexcept : m_Length(SIZE) , m_String(str) {} // 构造函数2:接受指针,运行时计算长度 constexpr BasicCharp(pointer string) noexcept : m_Length(countElems(string)) , m_String(string) {} private: size_t m_Length; pointer m_String; // 辅助函数:计算字符串长度 constexpr static size_t countElems(pointer str) noexcept { size_t len = 0; while (str[len] != '\0') { ++len; } return len; } };
当执行BasicCharp<const char> str = "test";时,由于非模板的构造函数2优先级高于模板的构造函数1,编译器会选择构造函数2,无法在编译时推导字符串字面量的长度。需求是保留构造函数2(用于传入指针的场景),但让字符串字面量优先使用构造函数1,实现编译时推导长度。
C++17解决方案
核心思路是将构造函数2改为模板函数,并通过SFINAE约束仅接受真正的指针类型,这样两个构造函数都是模板,此时数组引用的匹配会更精确,字符串字面量会优先选择构造函数1;而传入指针时,构造函数1不匹配,会选择构造函数2。
修改后的完整代码:
#include <type_traits> template <class CharType> class BasicCharp { public: using value_type = CharType; using pointer = value_type*; // 构造函数1:接受数组引用,编译时推导长度 template<size_t SIZE> constexpr BasicCharp(value_type (&str)[SIZE]) noexcept : m_Length(SIZE) , m_String(str) {} // 构造函数2:模板化,仅当参数为同类型指针时启用 template <typename Ptr, std::enable_if_t<std::is_pointer_v<Ptr> && std::is_same_v<std::remove_pointer_t<Ptr>, value_type>, int> = 0> constexpr BasicCharp(Ptr string) noexcept : m_Length(countElems(string)) , m_String(string) {} // 可选:暴露长度和指针,用于验证 constexpr size_t length() const noexcept { return m_Length; } constexpr pointer data() const noexcept { return m_String; } private: size_t m_Length; pointer m_String; constexpr static size_t countElems(pointer str) noexcept { size_t len = 0; while (str[len] != '\0') { ++len; } return len; } };
验证效果
- 当传入字符串字面量时:
constexpr BasicCharp<const char> str = "test"; static_assert(str.length() == 5); // 编译时通过,证明使用了构造函数1,推导了包含终止符的数组长度 - 当传入指针时:
const char* ptr = "hello"; BasicCharp<const char> str_ptr(ptr); // str_ptr.length() 会在构造时计算为6,使用构造函数2
原理说明
- 原问题中构造函数2是非模板函数,根据C++重载决议规则,非模板函数优先级高于模板函数,因此数组会隐式转换为指针并选择构造函数2。
- 修改后构造函数2变为模板函数,此时两个构造函数都是模板,编译器会选择匹配更精确的重载:字符串字面量是数组类型,构造函数1的数组引用参数匹配更直接,因此被优先选中;而指针参数无法匹配构造函数1,只能选择构造函数2。
内容的提问来源于stack exchange,提问作者DiKetarogg
相关产品推荐
相关产品推荐

