มีความแตกต่างระหว่างคำจำกัดความต่อไปนี้หรือไม่?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
หากไม่ต้องการรูปแบบใดใน C ++ 11
มีความแตกต่างระหว่างคำจำกัดความต่อไปนี้หรือไม่?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
หากไม่ต้องการรูปแบบใดใน C ++ 11
คำตอบ:
ฉันเชื่อว่ามีความแตกต่าง ลองเปลี่ยนชื่อพวกเขาเพื่อที่เราจะได้พูดคุยเกี่ยวกับพวกเขาได้ง่ายขึ้น:
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
ทั้งPI1
และPI2
คงที่ซึ่งหมายความว่าคุณไม่สามารถแก้ไขได้ แต่เพียง PI2
เป็นค่าคงที่เวลารวบรวม มันจะต้องเริ่มต้นในเวลารวบรวม PI1
อาจเริ่มต้นได้ในเวลารวบรวมหรือเวลาทำงาน นอกจากนี้สามารถใช้ได้เฉพาะ PI2
ในบริบทที่ต้องการค่าคงที่เวลารวบรวม ตัวอย่างเช่น:
constexpr double PI3 = PI1; // error
แต่:
constexpr double PI3 = PI2; // ok
และ:
static_assert(PI1 == 3.141592653589793, ""); // error
แต่:
static_assert(PI2 == 3.141592653589793, ""); // ok
เป็นสิ่งที่คุณควรใช้? ใช้แล้วแต่ความต้องการของคุณ คุณต้องการให้แน่ใจว่าคุณมีค่าคงที่เวลารวบรวมที่สามารถใช้ในบริบทที่ต้องการค่าคงที่เวลารวบรวมได้หรือไม่? คุณต้องการที่จะเริ่มต้นได้ด้วยการคำนวณทำในเวลาทำงาน? เป็นต้น
const int N = 10; char a[N];
ทำงานและขอบเขตของอาร์เรย์ต้องเป็นค่าคงที่เวลาคอมไพล์
PI1
เป็นค่าคงที่อินทิกรัลคอมไพล์เวลาสำหรับการใช้ในอาเรย์ แต่ไม่ใช่สำหรับใช้เป็นพารามิเตอร์เท็มเพลตแบบไม่มีชนิด ดังนั้นความสามารถในการคอมไพล์เวลาแปลงPI1
เป็นประเภทอินทิกรัลดูเหมือนจะเป็นเรื่องฮิตและพลาดไปสำหรับฉัน
enum
initializer เป็นเพียงความแตกต่างที่โดดเด่นเพียงสองอย่างระหว่างconst
และconstexpr
(และไม่สามารถใช้งานได้double
)
1 / PI1
และ1 / PI2
อาจให้ผลลัพธ์ที่แตกต่าง ฉันไม่คิดว่าเรื่องนี้เป็นเรื่องสำคัญพอ ๆ กับคำแนะนำในคำตอบนี้อย่างไรก็ตาม
constexpr double PI3 = PI1;
ทำงานได้อย่างถูกต้องสำหรับฉัน (MSVS2013 CTP) ผมทำอะไรผิดหรือเปล่า?
ไม่มีความแตกต่างที่นี่ แต่มันสำคัญเมื่อคุณมีประเภทที่มีคอนสตรัคเตอร์
struct S {
constexpr S(int);
};
const S s0(0);
constexpr S s1(1);
s0
เป็นค่าคงที่ แต่ไม่ได้รับประกันว่าจะเริ่มต้นได้ในเวลาคอมไพล์ s1
ถูกทำเครื่องหมายconstexpr
ดังนั้นจึงเป็นค่าคงที่และเนื่องจากคอนS
สตรัคเตอร์ของถูกทำเครื่องหมายconstexpr
ด้วยมันจะถูกเริ่มต้นในเวลารวบรวม
เรื่องนี้ส่วนใหญ่เมื่อเริ่มต้นที่รันไทม์จะใช้เวลานานและคุณต้องการที่จะผลักดันการทำงานที่ลงบนคอมไพเลอร์ที่มันยังต้องใช้เวลา แต่ไม่ช้าเวลาดำเนินการของโปรแกรมรวบรวม
constexpr
จะนำไปสู่การวินิจฉัยว่าการคำนวณเวลารวบรวมของวัตถุนั้นเป็นไปไม่ได้ สิ่งที่ชัดเจนน้อยกว่าคือฟังก์ชั่นที่คาดว่าพารามิเตอร์คงที่สามารถเรียกใช้งานในเวลาคอมไพล์ได้หรือไม่หากพารามิเตอร์นั้นถูกประกาศเป็นconst
และไม่เป็นเช่นconstexpr
: จะconstexpr int foo(S)
ถูกดำเนินการในเวลารวบรวมถ้าฉันเรียกfoo(s0)
?
foo(s0)
จะถูกประหารชีวิตในเวลารวบรวม แต่คุณไม่เคยรู้: คอมไพเลอร์ได้รับอนุญาตให้ทำการเพิ่มประสิทธิภาพดังกล่าว แน่นอนค่า GCC 4.7.2 มิได้เสียงดังกราว 3.2 ให้ฉันไปรวบรวมconstexpr a = foo(s0);
constexprบ่งชี้ค่าที่คงที่และเป็นที่รู้จักในระหว่างการรวบรวม
constระบุค่าที่คงที่เท่านั้น ไม่จำเป็นต้องรู้ในระหว่างการรวบรวม
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr
โปรดทราบว่า const ไม่ได้เสนอการรับประกันเช่นเดียวกับ constexpr เนื่องจากวัตถุ const ไม่จำเป็นต้องเริ่มต้นด้วยค่าที่ทราบในระหว่างการรวบรวม
int sz;
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation
วัตถุ constexpr ทั้งหมดเป็น const แต่ไม่ใช่วัตถุ const ทั้งหมดที่เป็น constexpr
หากคุณต้องการให้คอมไพเลอร์รับประกันว่าตัวแปรมีค่าที่สามารถใช้ในบริบทที่ต้องการค่าคงที่เวลาคอมไพล์เครื่องมือในการเข้าถึงคือ constexpr ไม่ใช่ const
constexprสัญลักษณ์คงต้องได้รับค่าที่เป็นที่รู้จักกันในเวลารวบรวม ตัวอย่างเช่น:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int c2 = n+7; // Error: we don’t know the value of c2
// ...
}
เพื่อจัดการกับกรณีที่ค่าของ“ ตัวแปร” ที่เริ่มต้นด้วยค่าที่ไม่รู้จักในเวลารวบรวม แต่ไม่เคยเปลี่ยนแปลงหลังจากเริ่มต้น C ++ มีรูปแบบที่สองของค่าคงที่ ( const ) ตัวอย่างเช่น:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int c2 = n+7; // OK, but don’t try to change the value of c2
// ...
c2 = 7; // error: c2 is a const
}
“ ตัวแปรconst ” นั้นเป็นเรื่องธรรมดามากด้วยเหตุผลสองประการ:
การอ้างอิง: "การเขียนโปรแกรม: หลักการและการฝึกใช้ C ++" โดย Stroustrup