2

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

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

  • тестирования строки равенства быстрее, чем stringconst char *
  • Исключите время выполнения накладных расходы неявных преобразований из const char * в string, которые требуют strlen() на постоянная время компиляции строк.
  • Compile времени струнные комплекты, которые делают равенство тестирование вместо хэширования для размера < N. (это несколько процессоров накладных расходов на одного приложения Я смотрю на)
+0

Если вы посмотрите на [ 'станд :: string' конструктор перегрузках] (http://en.cppreference.com/w/cpp/string/basic_string/basic_string) вы увидите, что они не делают даже беспокоиться с массивами, только указатели. –

+1

Они также не поддерживают конструкцию constexpr! В этом-то и дело. Шаблонный массив символов способен определять размер строки во время компиляции. –

+4

Функция без шаблонов имеет предпочтение по сравнению с шаблонами, даже если для этого требуется распад указателя. Однако я не знаю, как это исправить. У меня была та же проблема, когда я это пробовал, и, наконец, остановился на строках, основанных на вариационных шаблонах. – SergeyA

ответ

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>>()) {} 
+0

Впечатляет. Я пробовал что-то подобное, но не мог заставить его работать без трюка с указкой указателя. +1 для объяснения, почему 'const &' имеет значение. К сожалению, я не думаю, что смогу получить этот прошлый обзор кода, поскольку это осложняет путь кодов ванили. –