You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    

原理说明

  1. 原问题中构造函数2是非模板函数,根据C++重载决议规则,非模板函数优先级高于模板函数,因此数组会隐式转换为指针并选择构造函数2。
  2. 修改后构造函数2变为模板函数,此时两个构造函数都是模板,编译器会选择匹配更精确的重载:字符串字面量是数组类型,构造函数1的数组引用参数匹配更直接,因此被优先选中;而指针参数无法匹配构造函数1,只能选择构造函数2。

内容的提问来源于stack exchange,提问作者DiKetarogg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:20:40