Строки времени компиляции: приоритет перегрузки конструктора между `const char *` / `const char[]`

Я пытаюсь сделать класс строки времени компиляции. Я взял несколько подсказок из этого поста. К сожалению, я застрял на приоритете перегрузки конструктора: 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.

Я могу сделать много интересных вещей, если смогу создать строковые константы во время компиляции.

  • Тестирование на равенство строк выполняется быстрее string чем const char *
  • Устранить время выполнения неявных преобразований из const char * в string этот звонок strlen() на постоянных строках времени компиляции.
  • Наборы строк во время компиляции, которые выполняют тестирование на равенство вместо хеширования для размера

1 ответ

Это немного некрасиво, но это должно сработать:

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

Хитрость заключается в том, что взятие указателя с помощью константной ссылки блокирует затухание массива в указатель во время вывода аргумента шаблона, поэтому при передаче массива компилятор не может вывести 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>>()) {} 
Другие вопросы по тегам