เป็นไปได้ไหมที่จะใช้ std :: string ใน constexpr


175

โดยใช้ C ++ 11, อูบุนตู 14.04, toolchain

รหัสนี้ล้มเหลว:

constexpr std::string constString = "constString";

ข้อผิดพลาด: ประเภท 'สตริง const {aka const std :: basic_string}' ของตัวแปร constexpr 'constString' ไม่ใช่ตัวอักษร ... เพราะ ... 'std :: basic_string' มี destructor ที่ไม่สำคัญ

เป็นไปได้ที่จะใช้std::stringในconstexpr? (เห็นได้ชัดว่าไม่ใช่ ... ) ถ้าเป็นเช่นนั้นได้อย่างไร มีวิธีอื่นในการใช้สตริงอักขระในconstexpr?


2
std::stringไม่ใช่ประเภทที่แท้จริง
Piotr Skotnicki

7
@PiotrS - คำถามบอกว่า ...
เวกเตอร์

4
@Vector ฉันถามคุณว่า constexpr นั้นมีไว้เพื่ออะไรหรือทำไมคุณstd::stringถึงต้องการเป็น constexpr มีการใช้งานสตริงการคอมไพล์หลายครั้งบน SO อะไรคือจุดที่ถามว่าคุณสามารถสร้าง constexpr ที่ไม่ใช่ตัวอักษรได้หรือไม่ถ้าคุณเข้าใจข้อความแสดงข้อผิดพลาดและรู้ว่าสามารถสร้าง constexpr ได้อย่างไร มีหลายสาเหตุว่าทำไมคนเราอาจต้องการมีตัวอย่างของกลุ่มข้อความดังนั้นฉันขอแนะนำให้คุณอธิบายคำถามของคุณ
Piotr Skotnicki

2
ใช่เป็น @PiotrS กล่าวว่ามีconstexprการใช้งานสตริงออกมี std::stringไม่ใช่หนึ่งในนั้น
สิบสี่

3
@PiotrS - มีการใช้งานสตริงการคอมไพล์หลายครั้งใน SO - OK ขอบคุณเข้าใจ นั่นไม่ใช่ตัวเลือกสำหรับฉัน แต่มันตอบคำถามของฉัน: ไม่มีวิธี std :: string จะทำงาน ตามที่ฉันพูดถึงสิบสี่ฉันสงสัยว่ามีวิธีการใช้ std :: string ในวิธีที่จะทำงาน มีลูกเล่นมากมายที่ฉันไม่รู้ตัว
เวกเตอร์

คำตอบ:


167

ไม่และคอมไพเลอร์ของคุณได้ให้คำอธิบายที่ครอบคลุมแล้ว

แต่คุณสามารถทำได้:

constexpr char constString[] = "constString";

ที่รันไทม์สามารถใช้เพื่อสร้าง a std::stringเมื่อจำเป็น


78
ทำไมconstexpr auto constString = "constString";ล่ะ ไม่จำเป็นต้องใช้ไวยากรณ์อาร์เรย์ที่น่าเกลียด ;-)
stefan

80
ในบริบทของคำถามนี้มันชัดเจนกว่า ประเด็นของฉันเกี่ยวกับประเภทสตริงที่คุณสามารถเลือกได้ char[]ชัดเจนมากขึ้นกว่าautoตอนที่ฉันพยายามเน้นชนิดของข้อมูลที่จะใช้
สิบสี่

7
@tenfour ขวานั่นเป็นจุดที่ดี ฉันเดาว่าบางครั้งฉันก็มุ่งเน้นไปที่การใช้auto;-)
stefan

1
@ FelixDombek no แต่ด้วย c ++ 17 คุณสามารถใช้งานได้constexpr auto s = "c"sv;เนื่องจากการเปิดตัวของstring_view

6
มันเหมาะสมหรือไม่ที่จะใช้อาร์เรย์อักขระ char ในบริบทนั้น หากคุณใช้มันเพื่อสร้างสตริงมันจะถูกคัดลอกต่อไป อะไรคือความแตกต่างระหว่างการส่งตัวอักษรไปยังตัวสร้างสตริงและการส่งอาร์เรย์ 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 :: ใหม่จะต้องถูกสร้างขึ้น ซึ่งมักจะเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่เราคิดไว้เมื่อสร้างค่าคงที่ ดังนั้นฉันมักจะบอกว่านี่ไม่ใช่ความคิดที่ดี อย่างน้อยคุณต้องระวัง
Rambo Ramon

29
@RamboRamon string_viewไม่ได้โดยปริยายแปลงสภาพให้แก่stringจึงมีอันตรายเล็ก ๆ น้อย ๆ ไม่ได้ตั้งใจสร้างจากstring string_viewในทางกลับกันchar const* สามารถเปลี่ยนแปลงได้โดยปริยายstringดังนั้นการใช้string_viewจึงปลอดภัยกว่าในแง่นี้
Joseph Thomson

4
ขอขอบคุณสำหรับการชี้แจง. ฉันทั้งหมดเห็นด้วยและแน่นอนลืมไปว่าไม่ได้โดยปริยายแปลงสภาพให้แก่string_view stringIMO ปัญหาที่ฉันนำมาใช้นั้นยังคงใช้ได้ แต่ไม่ได้ใช้กับstring_viewเฉพาะ ในความเป็นจริงอย่างที่คุณพูดถึงมันปลอดภัยยิ่งกว่าในเรื่องนั้น
Rambo Ramon

5
มันจะดีถ้าคำตอบนี้พูดถึงสิ่งที่มากกว่าstring_viewจะเป็นแค่ลิงค์
eric

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

เนื่องจากปัญหาคือ destructor ที่ไม่สำคัญดังนั้นหาก destructor ถูกลบออกจาก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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.