ฉันพบพฤติกรรมแปลก ๆ ในขณะที่ใช้ลักษณะประเภท C ++ และได้ จำกัด ปัญหาของฉันให้แคบลงเหลือเพียงปัญหาเล็ก ๆ น้อย ๆ ที่เล่นโวหารซึ่งฉันจะให้คำอธิบายมากมายเนื่องจากฉันไม่ต้องการปล่อยให้มีการตีความที่ผิด
สมมติว่าคุณมีโปรแกรมดังนี้:
#include <iostream>
#include <cstdint>
template <typename T>
bool is_int64() { return false; }
template <>
bool is_int64<int64_t>() { return true; }
int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;
return 0;
}
ในการคอมไพล์ 32 บิตด้วย GCC (และ MSVC 32 และ 64 บิต) ผลลัพธ์ของโปรแกรมจะเป็น:
int: 0
int64_t: 1
long int: 0
long long int: 1
อย่างไรก็ตามโปรแกรมที่เกิดจากการคอมไพล์ GCC 64 บิตจะแสดงผลลัพธ์:
int: 0
int64_t: 1
long int: 1
long long int: 0
นี่คืออยากรู้อยากเห็นตั้งแต่long long int
เป็นลงนามจำนวนเต็ม 64 บิตและเป็นสำหรับ intents และวัตถุประสงค์เหมือนกับที่long int
และint64_t
ประเภทดังนั้นเหตุผลint64_t
, long int
และlong long int
จะเป็นประเภทเทียบเท่า - สร้างการชุมนุมเมื่อใช้ประเภทนี้เป็นเหมือนกัน ดูหนึ่งครั้งstdint.h
บอกฉันว่าทำไม:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
ในการคอมไพล์ 64 บิตint64_t
คือlong int
ไม่ใช่ a long long int
(ชัด ๆ )
การแก้ไขสถานการณ์นี้ค่อนข้างง่าย:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
แต่นี่เป็นการแฮ็กอย่างน่ากลัวและปรับขนาดได้ไม่ดี (หน้าที่จริงของสสารuint64_t
ฯลฯ ) คำถามของฉันคือ:มีวิธีบอกคอมไพเลอร์ไหมว่า a long long int
คือ a int64_t
เช่นเดียวกับlong int
is?
ความคิดเริ่มต้นของฉันคือมันเป็นไปไม่ได้เนื่องจากวิธีการทำงานของคำจำกัดความประเภท C / C ++ ไม่มีวิธีระบุประเภทความเท่าเทียมกันของชนิดข้อมูลพื้นฐานให้กับคอมไพเลอร์เนื่องจากนั่นคืองานของคอมไพเลอร์ (และการอนุญาตให้ทำสิ่งต่างๆมากมาย) และtypedef
ไปได้เพียงวิธีเดียว
ฉันไม่กังวลกับการได้รับคำตอบที่นี่มากนักเนื่องจากนี่เป็นกรณีสุดยอดที่ไม่คาดคิดว่าจะมีใครสนใจเมื่อตัวอย่างไม่ได้ถูกสร้างขึ้นอย่างน่ากลัว (นั่นหมายความว่านี่ควรเป็นวิกิชุมชนหรือไม่) .
ต่อท้าย : เหตุผลที่ฉันใช้ความเชี่ยวชาญพิเศษของเทมเพลตบางส่วนแทนที่จะเป็นตัวอย่างที่ง่ายกว่าเช่น:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
ตัวอย่างดังกล่าวจะยังคงคอมไพล์long long int
อยู่เนื่องจากโดยปริยายแปลงเป็นint64_t
ไฟล์.
ต่อท้าย : คำตอบเดียวที่สรุปได้ว่าฉันต้องการทราบว่าประเภทเป็น 64 บิตหรือไม่ ฉันไม่อยากทำให้คนเข้าใจผิดคิดว่าฉันสนใจเรื่องนั้นและน่าจะให้ตัวอย่างเพิ่มเติมว่าปัญหานี้ปรากฏตัวที่ใด
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
ในตัวอย่างนี้some_type_trait<long int>
จะเป็น a boost::true_type
แต่some_type_trait<long long int>
จะไม่เป็น แม้ว่าสิ่งนี้จะสมเหตุสมผลในความคิดของ C ++ แต่ก็ไม่เป็นที่ต้องการ
อีกตัวอย่างหนึ่งคือการใช้ qualifier เช่นsame_type
(ซึ่งเป็นเรื่องธรรมดาที่จะใช้ใน C ++ 0x Concepts):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
ตัวอย่างนั้นไม่สามารถคอมไพล์ได้เนื่องจาก C ++ (อย่างถูกต้อง) เห็นว่าประเภทต่างกัน กรัม ++ จะล้มเหลวในการรวบรวมกับข้อผิดพลาดที่ชอบ: same_type(long int&, long long int&)
ไม่มีการเรียกใช้ฟังก์ชันการจับคู่
ฉันอยากจะเน้นว่าฉันเข้าใจว่าเหตุใดจึงเกิดเหตุการณ์นี้ขึ้น แต่ฉันกำลังมองหาวิธีแก้ปัญหาที่ไม่บังคับให้ฉันต้องทำรหัสซ้ำในทุกที่
sizeof
แต่ละประเภทหรือไม่ บางทีคอมไพเลอร์กำลังปฏิบัติกับขนาดที่long long int
แตกต่างกัน