Можно ли использовать std :: string в constexpr?


175

Использование C ++ 11, Ubuntu 14.04, GCC по умолчанию .

Этот код не работает:

constexpr std::string constString = "constString";

ошибка: тип 'const string {aka const std :: basic_string}' переменной constexpr 'constString' не является литералом ... потому что ... 'std :: basic_string' имеет нетривиальный деструктор

Можно ли использовать std::stringв constexpr? (очевидно нет ...) Если так, то как? Есть ли альтернативный способ использовать строку символов в constexpr?


2
std::stringне буквальный тип
Петр Скотницкий

7
@PiotrS - вопрос говорит, что ...
Вектор

4
@Vector я спрашивал тебя, для чего нужен constexpr или почему ты хочешь std::stringбыть constexpr? Есть несколько реализаций строк во время компиляции в SO. Какой смысл спрашивать, можно ли сделать constexpr не буквальным типом, если вы понимаете сообщение об ошибке и знаете, что можно сделать только литеральные типы constexpr? также есть несколько причин, по которым можно хотеть иметь экземпляр constexpr, поэтому я предлагаю вам уточнить ваш вопрос
Петр Скотницкий

2
Да, как @PiotrS. сказал, что есть constexprреализации строк там. std::stringне один из них.
десять

3
@PiotrS - есть несколько реализаций строк во время компиляции на SO - хорошо, спасибо, понял. Это не вариант для меня, но он отвечает на мой вопрос: ни при каких условиях std :: string не будет работать. Как я заметил в tenfour, мне было интересно, есть ли способ использовать std :: string так, чтобы это работало. Есть много уловок, которые я, конечно, не знаю.
Вектор

Ответы:


167

Нет, и ваш компилятор уже дал вам исчерпывающее объяснение.

Но вы могли бы сделать это:

constexpr char constString[] = "constString";

Во время выполнения это может быть использовано для создания, std::stringкогда это необходимо.


78
Почему нет constexpr auto constString = "constString";? Нет необходимости использовать этот уродливый синтаксис массива ;-)
stefan

80
В контексте этого вопроса все понятнее. Моя точка зрения о том, какие типы строк вы можете выбрать. char[]более подробный / понятный, чем autoкогда я пытаюсь подчеркнуть тип данных для использования.
десять

7
@tenfour Правильно, это хороший момент. Я думаю, что иногда я слишком сосредоточен на использовании auto;-)
stefan

1
@FelixDombek нет, но с C ++ 17 можно использовать в constexpr auto s = "c"sv;связи с введениемstring_view
которым

6
Имеет ли смысл использовать массив символов в этом контексте? Если вы используете его для создания строки, она все равно будет скопирована. В чем разница между передачей литерала конструктору строки и передачей ему такого массива constexpr?
KjMag

169

Начиная с C ++ 20 , да.

Начиная с C ++ 17 , вы можете использовать string_view:

constexpr std::string_view sv = "hello, world";

string_viewЯвляется string-каком объекта , который действует как неизменная, не-владеющему ссылка на любую последовательность charобъектов.


6
Имейте в виду, что всякий раз, когда вы передаете эту константу в функцию, создающую const std::string&новую строку std :: string Обычно это противоположно тому, что вы имели в виду при создании константы. Поэтому я склонен говорить, что это не очень хорошая идея. По крайней мере, вы должны быть осторожны.
Рэмбо Рамон

29
@RamboRamon string_viewне является неявно конвертируемым в string, поэтому существует небольшая опасность случайного создания a stringиз a string_view. С другой стороны , char const* это неявное преобразование string, поэтому использование string_viewна самом деле безопаснее в этом смысле.
Джозеф Томсон

4
Спасибо за разъяснения. Я полностью согласен и действительно забыл, что string_viewне является неявно конвертируемым string. ИМО проблема, которую я поднял, все еще актуальна, но не относится к string_viewконкретно. На самом деле, как вы упомянули, в этом отношении еще безопаснее.
Рэмбо Рамон

5
Было бы здорово, если бы в этом ответе говорилось больше о том string_view, что есть, а не просто ссылка.
Эрик

23

C ++ 20 добавит constexprстроки и векторы

Следующее предложение было принято, по- видимому: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf и добавляет конструкторы, такие как:

// 20.3.2.2, construct/copy/destroy
constexpr
basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { }
constexpr
explicit basic_string(const Allocator& a) noexcept;
constexpr
basic_string(const basic_string& str);
constexpr
basic_string(basic_string&& str) noexcept;

в дополнение к constexpr версиям всех / большинства методов.

Начиная с GCC 9.1.0, поддержка отсутствует, компилируется следующее:

#include <string>

int main() {
    constexpr std::string s("abc");
}

с участием:

g++-9 -std=c++2a main.cpp

с ошибкой:

error: the type const string {aka const std::__cxx11::basic_string<char>’} of constexpr variable s is not literal

std::vectorобсуждается на: не может создать constexpr std :: vector

Проверено в Ubuntu 19.04.


19

Поскольку проблема заключается в нетривиальном деструкторе, поэтому, если деструктор удаляется из std::string, можно определить constexprэкземпляр этого типа. Как это

struct constexpr_str {
    char const* str;
    std::size_t size;

    // can only construct from a char[] literal
    template <std::size_t N>
    constexpr constexpr_str(char const (&s)[N])
        : str(s)
        , size(N - 1) // not count the trailing nul
    {}
};

int main()
{
    constexpr constexpr_str s("constString");

    // its .size is a constexpr
    std::array<int, s.size> a;
    return 0;
}

18
Это в основном то , что C ++ 17 string_viewявляется, за исключением того, что string_viewдает вам большую часть функциональных возможностей, которые вы знаете , изstd::string
которым
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.