การออกแบบคลาส constexpr: การรวมเวอร์ชัน constexpr และ non-constexpr เข้าด้วยกัน?

พิจารณาคลาสที่เพิ่งล้อมค่าที่รันไทม์ :

template <typename Type>
class NonConstValue 
{
    public:
        NonConstValue(const Type& val) : _value(val) {;}
        Type get() const {return _value;}
        void set(const Type& val) const {_value = val;}
    protected:
        Type _value;
};

และเวอร์ชัน constexpr ของสิ่งนั้น:

template <typename Type>
class ConstValue 
{
    public:
        constexpr ConstValue(const Type& val) : _value(val) {;}
        constexpr Type get() const {return _value;}
    protected:
        const Type _value;
};

คำถามที่ 1 : คุณยืนยันได้ไหมว่าเวอร์ชัน constexpr ได้รับการออกแบบมาอย่างถูกต้อง

คำถามที่ 2 : คุณจะผสมทั้งสองคลาสให้เป็นคลาสเดียวที่เรียกว่า Value ที่สามารถ constexpr สร้างหรือสร้างรันไทม์ได้อย่างไร และค่าใดที่สามารถเป็น get() ได้ที่รันไทม์หรือคอมไพล์ไทม์

แก้ไข: คำถามที่ 3: หากกำหนด get() ในไฟล์ .cpp และหากฉันต้องการให้ get() อยู่ในบรรทัดหากไม่ใช่ constexpr การประกาศที่ถูกต้องของฟังก์ชันคืออะไร ใช่ไหม

constexpr inline Type get();

or

inline constexpr Type get()

หรืออย่างอื่น ?


person Vincent    schedule 18.01.2013    source แหล่งที่มา
comment
constexpr สามารถเรียกใช้ฟังก์ชันในเวลาคอมไพล์หรือรันไทม์ได้   -  person chris    schedule 18.01.2013
comment
ฉันขอยืนยันว่าฟังก์ชันสมาชิก constexpr ที่ไม่คงที่มีข้อบกพร่องตรงที่พวกมันบ่งบอกถึงตัวระบุฟังก์ชัน const เสมอ นั่นคือ constexpr foo bar(); เป็นการประกาศเดียวกันกับ constexpr foo bar() const; ไม่มีข้อกำหนดดังกล่าวสำหรับผู้ที่ไม่ใช่สมาชิก เช่น constexpr foo bar(T&); หรือ constexpr foo bar(T&&); อาจยอมรับ non-const T ทั้งคู่ (และเป็นไปได้ที่จะมีนิพจน์คงที่ที่เกี่ยวข้องกับประเภทคลาสที่ผ่านการรับรองที่ไม่ใช่ const) ดังนั้นจงระวังสิ่งนั้นด้วย   -  person Luc Danton    schedule 18.01.2013


คำตอบ (2)


เพียงเพิ่มตัวระบุ constexpr ลงในแต่ละฟังก์ชันที่เป็น นิพจน์คงที่ ที่เป็นไปได้

template <typename Type>
class Value 
{
public:
    constexpr Value(Type const& val) : _value(val) {}
    constexpr Type const& get() const {return _value;}
    void set(Type const& val) {_value = val;}
protected:
    Type _value;
};

คุณไม่จำเป็นต้องมีเวอร์ชัน const และ non-const เนื่องจากสามารถทำได้โดยการสร้างอินสแตนซ์เทมเพลต Value ด้วย const หรือ < em>ไม่ใช่-const ประเภท

คุณไม่จำเป็นต้องมีเวอร์ชัน constexpr และ non-constexpr constexpr หมายถึง นิพจน์คงที่ ที่เป็นไปได้ และนิพจน์นั้นจะกลายเป็น นิพจน์คงที่หรือไม่นั้นขึ้นอยู่กับอาร์กิวเมนต์ของมัน การที่นิพจน์จะได้รับการประเมินที่ เวลาคอมไพล์ หรือไม่นั้น ขึ้นอยู่กับบริบทและการนำไปปฏิบัติ

person K-ballo    schedule 18.01.2013
comment
+1 สิ่งที่ฉันจะพูด อนุญาตให้ใช้ mutable ภายในวัตถุ constexpr ได้ - person Potatoswatter; 18.01.2013
comment
จู้จี้จุกจิกจริงๆ แต่ constexpr เป็นตัวระบุ ไม่ใช่ตัวประกาศ - person aschepler; 18.01.2013
comment
@aschepler: ขอบคุณ ฉันรู้ว่ามันไม่ใช่ตัวดัดแปลง แต่ฉันไม่มีคำที่ถูกต้อง - person K-ballo; 18.01.2013
comment
@Vincent: การเพิ่ม inline จะไม่ส่งผลต่อว่าฟังก์ชันจะอยู่ในบรรทัดหรือไม่ หากอยู่ใน .cpp อื่น ก็อาจจะไม่เป็นเช่นนั้น เนื่องจากคอมไพลเลอร์ไม่สามารถมองเห็นคำจำกัดความจากภายนอก .cpp ดังกล่าว - person K-ballo; 18.01.2013
comment
+1 สำหรับคำตอบที่ถูกต้อง หมายเหตุ: ไม่จำเป็นต้องประกาศ get() เป็นทั้ง constexpr และ const อดีตหมายถึงอย่างหลัง - person jogojapan; 18.01.2013
comment
คิดว่าการมี 2 ฟังก์ชันแยกกันยังคงมีประโยชน์ เนื่องจากฟังก์ชัน constexpr ไม่สามารถมี static locals ได้เหนือสิ่งอื่นใด - person ; 28.07.2015

คลาส constexpr ของคุณได้รับการออกแบบอย่างถูกต้อง ยกเว้นว่าคุณพิมพ์ชื่อของตัวสร้างผิด (ควรเป็น ConstValue ไม่ใช่ Value) แต่ฉันแน่ใจว่านั่นเป็นเพียงการพิมพ์ผิด

อินสแตนซ์ของเวอร์ชัน constexpr ของคุณสามารถใช้ได้ทั้งเป็นเวลาคอมไพล์และเป็นออบเจ็กต์รันไทม์

template <typename Type>
class ConstValue
{
    public:
        constexpr ConstValue(const Type& val) : _value(val) {;}
        constexpr Type get() const {return _value;}
    protected:
        const Type _value;
};

int main(int argc, char* argv[])
{
    int x[ConstValue<int>(3).get()];
}
person Andy Prowl    schedule 18.01.2013