Чи можна використовувати 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

167

Що стосується C ++ 20 , так.

Станом на C ++ 17 ви можете використовувати string_view:

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

A string_view- stringподібний об'єкт, який діє як незмінна, невласна посилання на будь-яку послідовність charоб'єктів.


6
Будьте в курсі, що кожного разу, коли ви передаєте цю константу функції, потрібно const std::string&створити нову строку std ::. Це, як правило, протилежне тому, що треба мати на увазі, створюючи константу. Тому я схильний говорити, що це не дуже гарна ідея. Принаймні треба бути обережними.
Рамбо Рамон

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

4
Дякуємо за роз’яснення. Я повністю згоден і дійсно забув, що string_viewце неявно не можна конвертувати string. ІМО проблема, яку я підніс, все ще діє, але не стосується string_viewконкретно. Насправді, як ви згадали, це навіть безпечніше в цьому плані.
Рамбо Рамон

5
Було б чудово, якби ця відповідь сказала більше про те, що string_viewє, а не просто посилання.
eric

22

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.