Можно ли использовать 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когда это необходимо.

tenfour
источник
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;
}
neuront
источник
18
Это в основном то , что C ++ 17 string_viewявляется, за исключением того, что string_viewдает вам большую часть функциональных возможностей, которые вы знаете , изstd::string
которым