Строки времени компиляции: приоритет перегрузки конструктора между `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>>()) {}