Có thể sử dụng chuỗi std :: trong constexpr không?


175

Sử dụng C ++ 11, Ubuntu 14.04, chuỗi công cụ mặc định GCC .

Mã này không thành công:

constexpr std::string constString = "constString";

lỗi: loại 'const chuỗi {aka const std :: basic_opes}' của biến constexpr 'constString' không theo nghĩa đen ... bởi vì ... 'std :: basic_opes' có hàm hủy không tầm thường

Có thể sử dụng std::stringtrong một constexpr? (dường như không ...) Nếu vậy, làm thế nào? Có cách nào khác để sử dụng chuỗi ký tự trong a constexprkhông?


2
std::stringkhông phải là một loại chữ
Piotr Skotnicki

7
@PiotrS - câu hỏi nói rằng ...
Vector

4
@Vector tôi đã hỏi bạn constexpr dùng để làm gì hay tại sao bạn muốn std::stringtrở thành constexpr? có một số triển khai chuỗi thời gian biên dịch trên SO. điểm quan trọng trong việc hỏi liệu bạn có thể tạo một constexpr không theo nghĩa đen không nếu bạn hiểu thông báo lỗi và chỉ biết các loại chữ có thể được tạo thành constexpr? cũng có một số lý do tại sao một người có thể muốn có một ví dụ constexpr, vì vậy tôi khuyên bạn nên làm rõ câu hỏi của mình
Piotr Skotnicki

2
Có như @PiotrS. cho biết, có constexprtriển khai chuỗi ra khỏi đó. std::stringkhông phải là một trong số họ.
tenfour

3
@PiotrS - có một số triển khai chuỗi thời gian biên dịch trên SO - OK, cảm ơn, đã hiểu. Đó không phải là một lựa chọn cho tôi nhưng nó trả lời câu hỏi của tôi: không có cách nào std :: string sẽ hoạt động. Như tôi đã nhận xét đến tenfour, tôi đã tự hỏi liệu có cách nào để sử dụng chuỗi std :: theo cách đó sẽ hoạt động không. Có nhiều thủ thuật mà tôi chắc chắn không nhận thức được.
Vector

Câu trả lời:


167

Không, và trình biên dịch của bạn đã cung cấp cho bạn một lời giải thích toàn diện.

Nhưng bạn có thể làm điều này:

constexpr char constString[] = "constString";

Trong thời gian chạy, điều này có thể được sử dụng để xây dựng std::stringkhi cần thiết.


78
Tại sao không constexpr auto constString = "constString";? Không cần sử dụng cú pháp mảng xấu xí đó ;-)
stefan

80
Trong bối cảnh của câu hỏi này, nó rõ ràng hơn. Quan điểm của tôi là về loại chuỗi bạn có thể chọn. char[]dài dòng / rõ ràng hơn so với autokhi tôi cố gắng nhấn mạnh kiểu dữ liệu sẽ sử dụng.
tenfour

7
@tenfour Phải, đó là một điểm tốt. Tôi đoán đôi khi tôi hơi quá tập trung vào việc sử dụng auto;-)
stefan

1
@FelixDombek không, nhưng với c ++ 17 bạn có thể sử dụng constexpr auto s = "c"sv;do sự ra đời củastring_view

6
Liệu nó có ý nghĩa để tạo ra một mảng char trong bối cảnh đó? Nếu bạn sử dụng nó để xây dựng một chuỗi, dù sao nó cũng sẽ được sao chép. Sự khác biệt giữa việc chuyển nghĩa đen cho hàm tạo của chuỗi và truyền một mảng constexpr như vậy cho nó là gì?
KjMag

167

Kể từ C ++ 20 , vâng.

Kể từ C ++ 17 , bạn có thể sử dụng string_view:

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

A string_viewlà một stringđối tượng giống như hoạt động như một tham chiếu bất biến, không sở hữu đối với bất kỳ chuỗi charđối tượng nào.


6
Xin lưu ý rằng bất cứ khi nào bạn truyền hằng số này cho một hàm lấy const std::string&chuỗi std :: mới phải được xây dựng. Điều đó thường trái ngược với những gì người ta có trong đầu khi tạo ra một hằng số. Do đó, tôi có xu hướng nói rằng đây không phải là một ý tưởng tốt. Ít nhất bạn phải cẩn thận.
Rambo Ramon

29
@RamboRamon string_viewkhông hoàn toàn có thể chuyển đổi thành string, do đó, có rất ít nguy cơ vô tình xây dựng a stringtừ a string_view. Ngược lại, char const* mặc nhiên chuyển đổi thành string, vì vậy sử dụng string_viewlà thực sự an toàn hơn theo nghĩa này.
Joseph Thomson

4
Cảm ơn bạn đã làm rõ. Tôi hoàn toàn đồng ý và thực sự quên rằng đó string_viewkhông phải là chuyển đổi hoàn toàn string. IMO vấn đề tôi đưa ra vẫn còn hiệu lực nhưng không áp dụng string_viewcụ thể. Trong thực tế, như bạn đã đề cập, nó thậm chí còn an toàn hơn trong vấn đề đó.
Rambo Ramon

5
Sẽ thật tuyệt nếu câu trả lời này nói nhiều hơn về những gì string_view, thay vì chỉ là một liên kết.
eric

22

C ++ 20 sẽ thêm constexprchuỗi và vectơ

Đề xuất sau đây đã được chấp nhận rõ ràng: http://www.open-std.org/jtc1/sc22/wg21/docs/ con / 2018 / p0980r0.pdf và nó thêm các nhà xây dựng như:

// 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;

ngoài các phiên bản constexpr của tất cả / hầu hết các phương thức.

Không có hỗ trợ nào kể từ GCC 9.1.0, sau đây không thể biên dịch:

#include <string>

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

với:

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

có lỗi:

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

std::vectorthảo luận tại: Không thể tạo constexpr std :: vector

Đã thử nghiệm trong Ubuntu 19.04.


19

Vì vấn đề là hàm hủy không tầm thường nên nếu loại bỏ hàm hủy khỏi std::string, nên có thể xác định một constexprthể hiện của loại đó. Như thế này

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
Về cơ bản, đây là c ++ 17 string_view, ngoại trừ việc string_viewcung cấp cho bạn hầu hết các chức năng mà bạn biết từstd::string
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.