3

我正在尝试制作一个编译时字符串类。我从这篇文章中得到了一些提示。不幸的是,我坚持构造函数重载优先级:const char[]构造函数被忽略而有利于 const char*构造函数。任何提示将不胜感激!

class string {
 public:
  // Can be done compile time. Works lovely! except...
  template<size_t N>
  constexpr string(const char(&char_array)[N])
      : ptr_(char_array), length_(N-1) {}

  // This override gets called instead.  I *must* keep this constructor.
  string(const char* const str)
      : ptr_(str) {
    length_ = strlen(str);
  }

  // Ugly hack. (not acceptable)
  template<size_t N>
  constexpr string(const char(&char_array)[N], double unused)
      : ptr_(char_array), length_(N-1) {}

 private:
  const char* ptr_;
  int length_;
};




constexpr const char kConstant[] = "FooBarBaz";

constexpr string kString(kConstant); // Error: constexpr variable 'kString' must be initialized by a constant expression (tries to call wrong overload)

constexpr string kString(kConstant, 1.0f); // ugly hack works.

如果我可以制作编译时字符串常量,我可以做很多很酷的事情。

  • 字符串相等性测试stringconst char *
  • 消除对编译时常量字符串的const char *调用string的隐式转换的运行时开销。strlen()
  • 执行相等性测试而不是散列大小 < N 的编译时字符串集。(这是我正在查看的一个应用程序的多个 CPU 开销)
4

1 回答 1

2

这有点难看,但它应该可以工作:

template<class T, class = std::enable_if_t<std::is_same_v<T, char>>>
string(const T * const & str)
    : ptr_(str) {
  length_ = strlen(str);
}

诀窍是在模板参数推导期间通过 const 引用获取指针会阻止数组到指针的衰减,因此当您传递数组时,编译器无法推导T并且构造函数被忽略。

缺点是这也会拒绝其他可以隐式转换为const char *.


另一种选择可能是接受可转换为 的所有内容const char *,然后根据所述事物是否为数组进行分派。

template<size_t N>
constexpr string(const char(&char_array)[N], std::true_type)
    : ptr_(char_array), length_(N-1) {}

string(const char * str, std::false_type)
    : ptr_(str) {
  length_ = strlen(str);
}

template<class T, class = std::enable_if_t<std::is_convertible_v<T, const char *>>>
constexpr string(T&& t) 
    : string(std::forward<T>(t), std::is_array<std::remove_reference_t<T>>()) {} 
于 2016-04-06T20:14:20.487 回答